Jan.Pechanec (at) Sun.COM
Version
Description
2008-05-11
some information on existing drafts added
2008-02-18
initial version of this document
This design document specifies how X.509v3 certificates should be used in SSH2 protocol within SunSSH for server authentication and user public key authentication. Note: using v3 certificates will not be necessary and KMF policy can be configured the way that no extensions are needed. This project has 3 different but mutually connected parts:
publickey authentication method)
| We will follow the latest IETF informational draft on X.509 authentication in SSH but if the draft becomes an RFC with incompatible changes we will follow RFC even if it involves losing backwards compatibility. |
There hasn't been much progress recently in IETF with regards to X.509v3
support in SSH. The last IETF document draft released on this topic
from the now defunct SSH working group was draft-ietf-secsh-x509-03.txt[1]. The draft expired on September
1, 2006 and specified 3 key and signature formats
x509v3-sign, x509v3-sign-rsa-sha1 and
x509v3-sign-dss-sha1. The most generic one,
x509v3-sign allowed use of a certificate chain for full PKIX path validation[4], together with sending optional OCSP
responses. However, before any RFC was released, IETF SSH
working group[9] closed down. From that reason, a new,
and now informational only draft[10] was released in the Network working group. The draft
expired on August 11, 2007 and no new version was released since then.
While the previous draft was about to define what it should be done, given
the fact that the group closed down, the new draft was released as
informational only, and its purpose was to inform what was implemented in
existing SSH software. The biggest difference in comparison to the draft filed
in SSH working group is the use of existing public key formats
ssh-(rsa|dsa). The problem with existing key formats is that
there is no way to define a chain of certificates. Both the host and client
certificates must be directly signed by a trusted anchor since there is no way
to communicate to the other side that there might be another certificate between
them.
Thanks to one of the author, Joseph Galbraith from Van Dyke, for clarification. There is a chance that the work on the last draft filed in SSH working group might be continued.
KMF provides a unified set of interfaces (both programming APIs and administrative tools) for managing PKI objects in Solaris. Currently, there are several different "keystore systems" that developers and administrators must choose when designing systems that employ PKI technologies - NSS, OpenSSL, and PKCS#11 are the 3 main choices. Each of these systems presents very different programming APIs and administrative tools and none of them has any sort of concept of a PKI policy enforcement system.
One of the unique features of KMF is that it provides a system-wide policy database that KMF can use to apply to applications. The administrator or user creates policy definitions in a database file. KMF applications can then choose which policy they want to assert and then all subsequent KMF operations will behave according to the limitations of that policy. Policy definitions include rules for how validation is to be performed, key usage and extended key usage requirements, trust anchor definitions, OCSP parameters, and CRL DB parameters (location, etc). This means that all parameters will be configured via the KMF policy mechanism. This should make SSH configuration simpler.
See KMF project[8] for more information.
The server has a certificate and a corresponding private host key. This certificate is sent to the client during key exchange (KEX), see [1]. Whether RSA or DSS host key algorithm will be offered depends on the server certificate (there can be only one server certificate). The private key is used to prove the server's identity during the server authentication[2]. The client is expected to trust (= have) the CA certificate that signed the server's certificate in order to proceed in the key exchange. We call such a certificate a Trusted Anchor (TA).
We use the HostKey keyword to specify the private key and
certificate. The certificate for the private key must be stored
using the same object label name. We need new option keywords for specifying
the server's KMF policy. Example for a server host (asiasf.sfbay.sun.com) key using a
pin in the URI (prototype version only):
HostKey="pkcs11:token=Sun Software PKCS#11 softtoken;pin=password;object=asiasf"
An existing server option (HostKey) will reference a private
key, and only PKCS#11 token rings will be supported for now. While the project
assumes the existence of other KMF plugins (OpenSSL, NSS) PKCS#11 will be the only supported
plugin for now. If the private key is:
HostKey will contain a pkcs#11
URI[3]. The certificate must be
signed directly by the TA, see existing IETF drafts section for more
information.
The PIN for a token could be specified using one of these methods:
sshd_config would have
to be made unreadable for all except root. Again, this doesn't seem like
a good solution, however it might make sense for debugging purposes only
- we could allow it only in debug mode.
The last suggestion appears to be the best solution since that way we can store the PIN in a file accessible by root only and the server configuration file can remain readable for all. The security of this solution is not a regression from current behaviour as the host private keys are protected by UNIX file permissions only.
The client specifies policies for individual servers, through
Host sections in the client's config file. Every policy
specifies one trusted anchor via ta-name and
ta-serial attributes of the kmf-policy element. See
kmfcfg(1) for more information.
The KMFPolicyDatabase option keyword will be used to set
the KMF policy file, KMFPolicyName will specify a policy
name. The default value will be empty. If at least one of them is non-empty,
x509v3-sign-(rsa|dss) will be added to the host key
algorithms for key exchange, and will be preferred. Whether RSA or DSS type will
be added will be decided from the TA certificate. It is up to the administrator
to correctly specify KMF policy. For example, to make sure that TA certificate
specified in the policy is accessible. So far, the name for the PKCS#11 keystore
for the TA's location can't be in the policy database. The KMF team is working
on a solution, we will rely on that and won't provide an additional
option keyword.
OCSP support is not SunSSH's job. This is taken care of through KMF policy, see kmfcfg(1) man page[5].
In general, a server certificate that contains id-ad-ocsp in
the certificate's accessMethod extension, together with a KMF
policy that specifies OCSP in the validation-methods element and
apropriate attributes of the ocsp-basic element, will be checked
using OCSP during certificate validation. In that case,
accessLocation will be used if uri-from-cert is set
in the policy file. See also /etc/security/kmfpolicy.xml[6].
As with OCSP, defining CRL support is out of scope of SunSSH and is also done through client KMF policy, see kmfcfg(1) man page[5].
In general, a server certificate that contains the cRLDistributionPoints extension, together with a KMF policy that specifies a CRL in the validation-methods element and apropriate attributes of the crl element, will be checked in the certificate revocation list.
Similar to server authentication, the client specifies its private host keys
and a corresponding certificates. The only difference is that
IdentityFile is used instead of HostKey
and that the client can specify more keys in KMF keystores.
The PIN will be asked for before any connection is established. However, using modified SSH agent might be encouraged. We will also provide a similar attribute as for the server - to set an external command which provides the PIN.
Similar to the client side of server authentication, the server specifies a
trusted anchor via the ta-name and ta-serial
attributes of the kmf-policy element in the KMF policy. For now,
we can have only one Trusted Anchor per SunSSH server. However, this
could probably be extended to multiple policies through resyncing the
Match option keyword from OpenSSH. See RFE 6655613[7] for more information.
See server authentication -- this will be configured through KMF policy, not SunSSH.
We must modify the SSH agent for X.509v3 support. One issue we see is how to keep a private key in the agent, expecially when we expect that users will use smart cards that won't allow any private keys to be extracted. Storing private keys corresponding to X.509v3 certificates in the agent is not a good solution.
The agent needs a handle for every private key in a keystore to sign data
requests. The problem is how to provide an agent with the key handle. The ideal
situation would be if ssh-add asked for a PIN, got a KMF
session and a private key handle and passed that to the agent. That's not
possible but we can provide the agent with a PIN. So,
ssh-add will ask for a PIN and add it to a PKCS#11 URI that
is sent in a comment field to the agent. There is no need to extend the agent
protocol.
When listing the keys we can't provide a fingerprint since we might not have
access to the private key (remember, signing may happen inside of a hardware
token). So, we could provide a DN for the corresponding certificate instead,
maybe in double quotes for easier parsing, and type of the keystore.
ssh-add -L could then list the whole certificate.
$ ssh-add -l 1024 90:44:85:88:e6:d4:b8:54:a7:89:5d:e3:94:90:51:08 .ssh/id_dsa (DSA) 1024 "CN=jp,C=CZ,ST=Czech Republic" pkcs11-keystore (X509/RSA)
If the agent protocol needed to be extended we should probably do that through IETF. As far as I know, there is no existing RFC defining the protocol, only a very old draft[11]. Thus, OpenSSH (and SunSSH) uses the protocol as defined in the original SSH specification[12], with some extensions. Having described current situation, I think that no new extensions should be used without re-opening the discussion about the protocol.
When the receiving party gets a certificate for a specified server or user, there needs to be a way to decide that the certificate was really issued for that server host or user name. So, we need a way how to map a certificate to a FQDN, IP address, UNIX user name or UNIX UID.
Unfortunately, that's not part of KMF yet but is planned as a future project. We expect that mapping will be tied to a specified TA and that there is no need to change it per connection on the receiving side. Another assumption is that certidicate-to-username mapping will be configurable through the KMF policy only. We don't want to configure through SunSSH which certificate field is to be used for a host or a client name, or possibly how such field should be rewritten.
The username we get from KMF according to policy settings must be equal to
what we get from 2nd field in SSH_MSG_USERAUTH_REQUEST SSH packet,
see RFC 4252[13] for more information.
We don't intend to support adding @domainname suffix, for example,
at least not in the 1st phase of this project.
More interesting than username mapping is hostname mapping. Whether we get the hostname as specified in the certificate from CN, AltName or something else will be up to the KMF mapping as configured in the policy.
The interesting part is what hostname to use for comparison to the hostname
extracted from the certificate. We can't look up and use a canonical name for
the host specified on the command line (say,
good-guy.company.com) since we could get a different
canonical hostname (say, bad-guy.company.com) and IP adress
from a compromised DNS server. However, the certificate sent for
bad-guy.company.com might have been signed by a valid CA
so we could end up connected to a different server than we wanted. In that
case, the compromised DNS server and one host with a valid certificate could be
enough to impersonate any other host. User wouldn't notice that at all during
the server authentication -- remember, we don't have any location bar where you
might notice the change between hostnames.
From that reason, we must always use a hostname in the form as was specified
on the command line or in the HostName option. That means
that users might be required to use hostnames in FQDN form because that's what
we suppose is going to be used in host certificates. Or, if CA is willing to sign
certificates with short names like my-machine, users could
use short names. Important thing is that if we had a compromised DNS server and
one compromised machine as in the previous situation,
bad-guy.company.com machine couldn't impersonate
my-machine now since we couldn't be tricked into using a
different hostname. Machine bad-guy.company.com would have
to posses my-machine's private key in order to mount the
attack.
Having to use the hostname exactly in the form as specified in the
certificate might be annoying. We might want to offer a list of domains that
could be used to complete the hostname before doing the comparison. Obvious
candidate /etc/resolv.conf is not good enough because a
different naming service might be in use. One option would be to use the
KMFDomainNames-like option with a list of domain names. In
corporate environment, we expect that internal CAs would issue host certificates
with unified hostnames so adding such option with
my-company.com domain name into a system wide
ssh_config might be useful.
If a user uses an IP address, the client would use the exact IP address as specified for comparison.
A new policy template for sshd/ssh will be delivered with the SunSSH packages. We might even ship more example policy templates, showing example of OCSP vers CRL usage etc.
As with the current implementation of public key user authentication,
sshd will not call
pam_authenticate(3PAM) for authentication, only for account
management and session management.
This is how client prototype is used:
ssh -p 2222 \
-o KMFPolicyDatabase=/etc/security/testpolicy.xml \
-o KMFPolicyName=test
-o IdentityFile="pkcs11:token=Sun Software PKCS#11 softtoken;object=jp" \
asiasf.sfbay
This is server prototype is used:
sshd -p 2222 \
-o HostKey="pkcs11:token=Sun Software PKCS#11 softtoken;object=asiasf" \
-o KMFPolicyDatabase=/etc/security/testpolicy.xml \
-o KMFPolicyName=test
And in the soft token on the client side there is a test TA certificate (label is "ta") and a certificate for the user "jp", together with a private key.
$ pktool list objtype=both
Enter PIN for Sun Software PKCS#11 softtoken :
Found 1 asymmetric private keys.
Key #1 - RSA private key: jp
Found 2 certificates.
1. (X.509 certificate)
Label: ta
ID: 74:23:e3:ea:d7:f7:42:db:bf:78:c8:a5:d6:82:7e:c8:70:03:8a:81
Subject: C=CZ, ST=Czech Republic, CN=authority
Issuer: C=CZ, ST=Czech Republic, CN=authority
Not Before: Jan 23 12:57:00 2008 GMT
Not After: Jan 22 12:57:00 2009 GMT
Serial: 0x01
2. (X.509 certificate)
Label: jp
ID: 86:05:e8:53:b3:fb:7a:80:8c:c1:61:50:87:5c:80:1a:49:a6:fe:66
Subject: C=CZ, ST=Czech Republic, O=Sun, OU=Sec, CN=jp
Issuer: C=CZ, ST=Czech Republic, CN=authority
Not Before: Feb 5 14:32:29 2008 GMT
Not After: Feb 4 14:32:29 2009 GMT
Serial: 0x05
X509v3 Key Usage: Digital Signature, Non Repudiation, Key Encipherment
KMF policy is very simple - the TA's DN was added to the template. Remember
that the policy file is configured through kmfcfg(1) - there
is no need to manually edit it.
$ cat /etc/security/testpolicy.xml
<?xml version="1.0"?>
<!DOCTYPE kmf-policy-db SYSTEM "/usr/share/lib/xml/dtd/kmfpolicy.dtd">
<kmf-policy-db>
<kmf-policy name="test" ta-name="C=CZ, ST=Czech Republic, CN=authority" ta-serial="0x01">
<validation-methods>
</validation-methods>
</kmf-policy>
</kmf-policy-db>
known_host file so that we could later
operate without a CA certificate and trust the server if IP/pub-key are
the same?
ssh-keygen won't be
modified to generate certificates, sign them etc. There
are other tools to do that
(pktool(1) or OpenSSL, for example).
KMFDomainNames. See Security of
certificate to hostname mapping for more information.
/etc/security/kmfpolicy.xml in
any OpenSolaris distribution