Bug 834718

Summary: backport RT#7183 to allow PKINIT to process signedData which omits the certificates list
Product: Red Hat Enterprise Linux 6 Reporter: Nalin Dahyabhai <nalin>
Component: krb5Assignee: Nalin Dahyabhai <nalin>
Status: CLOSED ERRATA QA Contact: Zbysek MRAZ <zmraz>
Severity: medium Docs Contact:
Priority: medium    
Version: 6.3CC: dpal, ebenes, jplans, ksrot, prc
Target Milestone: rc   
Target Release: ---   
Hardware: Unspecified   
OS: Unspecified   
Whiteboard:
Fixed In Version: krb5-1.10.3-5.el6 Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2013-02-21 08:37:04 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:

Description Nalin Dahyabhai 2012-06-22 21:28:40 UTC
If a PKINIT client uses the KDC's own certificate as a trust anchor, then it will include information identifying the KDC's certificate in the list of anchors which it trusts, which it passes to the KDC as part of its request.

A Heimdal 1.2.1 KDC (and, I suspect, later versions, though I haven't personally verified this), when signing data, will omit any such anchors from the list of certificates which it includes in the signed data structure, persumably under the assumption that the client already has a copy of the signer certificate.

Without the fix from RT, the client assumes that the signer's certificate is in the signed data structure, and if it isn't (as is the case here), it will fail to verify the signed data, and PKINIT will fail (kinit will fall back to prompting for a password).  Basically, the client should be able to handle cases where the signer's certificate isn't in the signed data structure, but where the client already has a copy of the KDC's certificate, either configured as an anchor or in the pool of possible intermediates.

Comment 2 Nalin Dahyabhai 2012-08-13 19:18:37 UTC
You'll need to set up a KDC using Heimdal 1.2.1.  Newer versions should
work as well (it's not like it's a bug in Heimdal), but I haven't personally
checked:

  yum -y install openssl-devel gcc binutils make automake autoconf db4-devel
  curl -o heimdal-1.2.1.tar.gz http://www.h5l.org/dist/src/heimdal-1.2.1.tar.gz
  tar xzf heimdal-1.2.1.tar.gz
  cd heimdal-1.2.1
  ./configure --prefix=/usr/heimdal --disable-shared
  make all install

You'll need a CA and certificates for the client and the KDC.  I'm going
to skip over the details here [1], since they're going to vary depending
on your CA, but the important parts are:
  * The KDC's certificate needs to include the Kerberos principal name
    "krbtgt/$REALM@$REALM" stored in it, as detailed in RFC4556, and it
    needs to be marked as a KDC by having an EKU of 1.3.6.1.5.2.3.5.
  * The client's certificate needs to include the Kerberos principal
    name "$CLIENT@$REALM" stored in it, as detailed in RFC4556, and it
    needs to be marked as a PKINIT client by having an EKU of
    1.3.6.1.5.2.3.4.

While both the client and the KDC support multiple formats for this data, I'm
going to assume that you have certificates for the CAs that issued the client
and KDC's certificates in PEM-formatted files named $KDC_CA.crt and
$CLIENT_CA.crt.  They can be the same.  I'm also going to assume that your
KDC's hostname is "$KDC", and its certificate and private key are wrapped up in
a binary PKCS12 bundle named $KDC.p12, and that you have a second copy of the
KDC's certificate in a PEM-formatted file named $KDC.crt, and your client's are
in a binary PKCS12 bundle named $CLIENT.p12.

On the KDC, use kadmin to create the realm database and a client account
for the user:

  mkdir -p /var/heimdal/heimdal
  /usr/heimdal/sbin/kadmin --realm=$REALM --local init $REALM
  /usr/heimdal/sbin/kadmin --realm=$REALM --local ank $CLIENT@$REALM

Configure the client to trust the KDC's issuer, and its own.  In
/etc/krb5.conf, this means adding this to the [realms] section:

 [realms]
  $REALM = {
    pkinit_anchors = FILE:/path/to/$KDC_CA.crt
    pkinit_anchors = FILE:/path/to/$CLIENT_CA.crt
  }

Likewise, on the KDC, /var/heimdal/kdc.conf should instruct the KDC
to trust its own CA and the client's CA, and it should tell the KDC
where to find its PKI credentials:

 [kdc]
   enable-pkinit = true
   pkinit_anchors = FILE:/path/to/$KDC_CA.crt
   pkinit_anchors = FILE:/path/to/$CLIENT_CA.crt
   pkinit_identity = PKCS12:/path/to/$KDC.p12

On the client, make sure krb5-pkinit-openssl is installed, and use kinit
to try to use the client's PKI creds to get credentials:

  kinit -X X509_user_identity=PKCS12:/path/to/$CLIENT.p12 $CLIENT

If you're using a smart card, for example a CoolKey, point to the
PKCS11 plugin which is used to access the card instead:

  kinit -X X509_user_identity=PKCS11:/path/to/libcoolkeypk11.so $CLIENT

If this fails, set "KRB5_TRACE=/dev/stderr" in your environment and try
it again to get some more detailed trace output.

If it succeeds, then PKINIT is working.  Now break it by adding the
KDC's own certificate to the anchors list on the client, so that your
list in the client's /etc/krb5.conf looks more like this:

 [realms]
  $REALM = {
    pkinit_anchors = FILE:/path/to/$KDC_CA.crt
    pkinit_anchors = FILE:/path/to/$CLIENT_CA.crt
    pkinit_identity = FILE:/path/to/$KDC.crt
  }

Try running kinit again, as before.  If it fails and falls back to
prompting for $CLIENT's Kerberos password, and you see "Preauth module pkinit (17)
(flags=1) returned: -1765328360/Preauthentication failed" in the trace output, you're
seeing the client reject the server's response to its attempt to use PKINIT, which is
most likely due to the bug.

[1] For testing purposes, this part can be done with a script.  Your
    KDC's name should be in lower-case, and your realm name should be in
    upper case.  (This is usually the case, but the script we're using
    uses case to tell the difference between email addresses and
    principal names, so it's a hard requirement.)
  wget -c http://git.fedorahosted.org/cgit/pkinit-nss.git/plain/doc/openssl/make-certs.sh
  chmod +x make-certs.sh
  KDC=`hostname`
  REALM=BADVOCACY.NET
  CLIENT=testuser
  CLIENTNAME="Test User"
  ./make-certs.sh $KDC root@$KDC \
      id-pkinit-kdc tls-server \
      encrypt sign \
      krbtgt/$REALM@$REALM
  ./make-certs.sh "$CLIENTNAME" $CLIENT@$KDC \
      id-pkinit-client tls-client \
      encrypt sign \
      $CLIENT@$REALM
  ln -s ca.crt $KDC_CA.crt
  ln -s ca.crt $CLIENT_CA.crt
  ln -s "$CLIENTNAME".p12 $CLIENT.p12

Comment 9 errata-xmlrpc 2013-02-21 08:37:04 UTC
Since the problem described in this bug report should be
resolved in a recent advisory, it has been closed with a
resolution of ERRATA.

For information on the advisory, and where to find the updated
files, follow the link below.

If the solution does not work for you, open a new bug report.

http://rhn.redhat.com/errata/RHBA-2013-0319.html