Problem: no root certificates generated for some non-english locales.

In this message, first, I describe the problem, then the solution. Many
users may have the bug, so a test is necessary. This test is described
below.

I am most greatful to Ken Moffat for reading a first draft and giving
important suggestions that changed the text in many places. Other than
technical input and corrections to my poor English: "... unsecure
communication ? That definitely needs to be noted. ... publicizing the
issue sooner rather than later will be the right thing to do". So I will.

First, I give my locale:

$ echo $LANG
pt_BR.utf8

I believe this is not just my problem. It seems to be a problem with
mkcacerts.sh, the script for generating cacerts for OpenJDK. In my logs,
I could find the problem since version 1.7.0.9. I have installed many
versions, the last one being 1.7.0.40 (this one has been installed with
IcedTea 2.4.0 and 2.4.1). Or the problem is with the other ones
involved, OpenSSL and OpenJDK.

Or not any of them individually, but a combination of what one expects
and the other one gives (input/output).

Perhaps it is not a critical bug, but it has to be reported, as it
involves security, as noted above by Ken. I think the the support list
should be informed, due to the nature of the problem.

This problem is caused by the following instruction in mkcacerts.sh:

    echo yes | "${KEYTOOL}" -import -alias `basename "${cert}"` -keystore \
                   "${OUTFILE}" -storepass 'changeit' -file "${tempfile}"

I have just downloaded OpenJDK-1.7.0.9 and tested it.

<http://anduin.linuxfromscratch.org/files/BLFS/OpenJDK-1.7.0.9/OpenJDK-1.7.0.9-i686-bin.tar.xz>

The script mkcacerts.sh fails to generate the certificates, for my
locale ince 1.7.0.9. Simply put, *not even an empty cacerts* is
generated, null.

To demonstrate, Just untar OpenJDK-1.7.0.* in a temporary directory, cd
OpenJDK-1.7.0.*, copy the script into here, and issue:

sh mkcacerts.sh -d "/etc/ssl/certs/" -k "bin/keytool" -s
"/usr/bin/openssl" \
    -o "../"

Result (for my locale) is no cacerts at ../ at all:

$ ls -l ..
total 4
drwxr-xr-x 9 fernando fernando 4096 Jul 19 19:43 OpenJDK-1.7.0.9-i686-bin
$

I just checked if by any chance it was placed elsewhere, but only one
from the tarball, dated from Oct 21  2012.

In the logs, I find the error:

$ xzless
../../mkcacerts.sh-pt_BR.utf8-1.7.0.9-i686-bin-blfs-anduin-2013.07.19.log.xz

...

/etc/ssl/certs/cfa1c2ee.pem
Proprietário: CN=Buypass Class 2 CA 1, O=Buypass AS-983163327, C=NO
...
Fingerprints do certificado:
...
Extensões:

#1: ObjectId: 2.5.29.19 Criticality=true
...
Confiar neste certificado? [não]:  Resposta errada; tente novamente
Confiar neste certificado? [não]:  erro de keytool:
java.lang.NullPointerException
...


This is, I think, the problem: "não" instead of "no" and "sim", instead
of "yes".

Solution? Use LC_ALL=C to run the script or, inside the script, write

echo yes |  LC_ALL=C "${KEYTOOL}" -import -alias `basename "${cert}"` \
    -keystore "${OUTFILE}" -storepass 'changeit' -file "${tempfile}"

This is what I think is easier, because only one place in the OpenJDK
cacerts patch needs to be modified.

This finishes the presentation of the problem.

Now, starting to describe the solution, so that anyone can correct an
eventually faulty installation. Also, if you have updated the system's
root certificates, after the installation of OJDK, the procedure
described can be used to updated the OJDK root certificates. Perhaps
instructions below for that could be included in the page "Certificate
Authority Certificates".

Having demontrated the problem is not only for the present version, from
here on, consider just present version in the book.

Test if the root certificates have been installed. If you obtain a
result with last line:

"Your keystore contains 0 entries"

then you need to install them, you have none. The number of entries has
to be non-zero, obviously, if the certificates are installed. To make
the test:

$ cd opt/OpenJDK-1.7.0.40
$ env LC_ALL=C bin/keytool -list -keystore jre/lib/security/cacerts

Enter keystore password:

*****************  WARNING WARNING WARNING  *****************
* The integrity of the information stored in your keystore  *
* has NOT been verified!  In order to verify its integrity, *
* you must provide your keystore password.                  *
*****************  WARNING WARNING WARNING  *****************

Keystore type: JKS
Keystore provider: SUN

Your keystore contains 0 entries
$

At "Enter keystore password:", just hit enter, if the password has not
yet been
defined. Meaning of the message is obvious.

If you have this problem, after the procedure below, the root
certificates will
be installed.

After correctly installed, the result can be tested with the same command
above, in which case, all certificates and repective properties will be
listed,
or, to simplify the output, use grep:

$ cd opt/OpenJDK-1.7.0.40
$ env LC_ALL=C bin/keytool -list -keystore jre/lib/security/cacerts \
      | grep entries
Enter keystore password:

*****************  WARNING WARNING WARNING  *****************
* The integrity of the information stored in your keystore  *
* has NOT been verified!  In order to verify its integrity, *
* you must provide your keystore password.                  *
*****************  WARNING WARNING WARNING  *****************

Your keystore contains 157 entries
$

(Again, just hit enter at the password prompt.)

PROCEDURE TO INSTALL OR UPDATE THE ROOT CERTIFICATES FOR OpenJDK

1. How To Obtain A Good Patch For A Fresh Build
2. Generating The Certificate File
3. Manual Installation Of Certificates
4. How To Obtain A Good Script
5. Difference Between Original And New Scripts
6. Difference Between Original And New Patches

Items 1. to 3. have explanations. The others are more like apendixes.

1. How To Obtain A Good Patch For A Fresh Build

First, correct the patch to run the most iportant command in locale C:

sed 's/echo yes | /echo yes | env LC_ALL=C /' \
    icedtea-2.4.1-add_cacerts-1.patch > icedtea-2.4.1-add_cacerts-2.patch

As described earlier, this will make the reply expected by keytool to be
yes/no, instead of sim/não. No certificate was accepted with the old
patch, because it was expecting "sim" and received "yes".

2. Generating The Certificate File

Further below, find a good mkcacerts.sh script.
#(by DJ and BD, small modification as above by FO).

Change to OpenJDK-1.7.0.40 directory. If it is in /opt, then everything
must be run as root. Make sure you do not have a file name certificates
at ../, as it will be overwritten.

sh mkcacerts.sh -d "/etc/ssl/certs/"  -k "bin/keytool" \
                -s "/usr/bin/openssl" -o "../certificates"

If you have my locale installed, you can test the original script, to
find that it probably fails using the procedure above, with the command

env LC_ALL=pt_BR.utf8 sh mkcacerts.sh ...

On the contrary, if you have a locale with problem, as mine, and have an
original script as in the cacerts patch of BLFS, correct certificates
can be obtained, alternatively, using:

env LC_ALL=C sh mkcacerts.sh ...

3. Manual Installation Of Certificates

It is better to backup, first:

mv -vi jre/lib/security/cacerts{,-back}

Now, certificates can be properly installed.

cp -v ../certificates jre/lib/security/cacerts
chown -c 0:0          jre/lib/security/cacerts
chmod -c 0644         jre/lib/security/cacerts

4. How To Obtain A Good Script

$ cat > mkcacerts.sh << "EOF" &&
#!/bin/sh
# Simple script to extract x509 certificates and create a JRE cacerts file.

function get_args()
    {
        if test -z "${1}" ; then
            showhelp
            exit 1
        fi

        while test -n "${1}" ; do
            case "${1}" in
                -f | --cafile)
                    check_arg $1 $2
                    CAFILE="${2}"
                    shift 2
                ;;
                -d | --cadir)
                    check_arg $1 $2
                    CADIR="${2}"
                    shift 2
                ;;
                -o | --outfile)
                    check_arg $1 $2
                    OUTFILE="${2}"
                    shift 2
                ;;
                -k | --keytool)
                    check_arg $1 $2
                    KEYTOOL="${2}"
                    shift 2
                ;;
                -s | --openssl)
                    check_arg $1 $2
                    OPENSSL="${2}"
                    shift 2
                ;;
                -h | --help)
                     showhelp
                     exit 0
                ;;
                *)
                   showhelp
                   exit 1
                ;;
            esac
        done
    }

function check_arg()
    {
        echo "${2}" | grep -v "^-" > /dev/null
        if [ -z "$?" -o ! -n "$2" ]; then
            echo "Error:  $1 requires a valid argument."
            exit 1
        fi
    }

# The date binary is not reliable on 32bit systems for dates after 2038
function mydate()
    {
        local y=$( echo $1 | cut -d" " -f4 )
        local M=$( echo $1 | cut -d" " -f1 )
        local d=$( echo $1 | cut -d" " -f2 )
        local m

        if [ ${d} -lt 10 ]; then d="0${d}"; fi

        case $M in
            Jan) m="01";;
            Feb) m="02";;
            Mar) m="03";;
            Apr) m="04";;
            May) m="05";;
            Jun) m="06";;
            Jul) m="07";;
            Aug) m="08";;
            Sep) m="09";;
            Oct) m="10";;
            Nov) m="11";;
            Dec) m="12";;
        esac

        certdate="${y}${m}${d}"
    }

function showhelp()
    {
        echo "`basename ${0}` creates a valid cacerts file for use with
IcedTea."
        echo ""
        echo "        -f  --cafile        The path to a file containing
PEM formated CA"
        echo "                            certificates.  May not be used
with -d/--cadir."
        echo "        -d  --cadir         The path to a diectory of PEM
formatted CA"
        echo "                            certificates.  May not be used
with -f/--cafile."
        echo "        -o  --outfile       The path to the output file."
        echo ""
        echo "        -k  --keytool       The path to the java keytool
utility."
        echo ""
        echo "        -s  --openssl       The path to the openssl utility."
        echo ""
        echo "        -h  --help          Show this help message and exit."
        echo ""
        echo ""
    }

# Initialize empty variables so that the shell does not polute the script
CAFILE=""
CADIR=""
OUTFILE=""
OPENSSL=""
KEYTOOL=""
certdate=""
date=""
today=$( date +%Y%m%d )

# Process command line arguments
get_args ${@}

# Handle common errors
if test "${CAFILE}x" == "x" -a "${CADIR}x" == "x" ; then
    echo "ERROR!  You must provide an x509 certificate store!"
    echo "\'$(basename ${0}) --help\' for more info."
    echo ""
    exit 1
fi

if test "${CAFILE}x" != "x" -a "${CADIR}x" != "x" ; then
    echo "ERROR!  You cannot provide two x509 certificate stores!"
    echo "\'$(basename ${0}) --help\' for more info."
    echo ""
    exit 1
fi

if test "${KEYTOOL}x" == "x" ; then
    echo "ERROR!  You must provide a valid keytool program!"
    echo "\'$(basename ${0}) --help\' for more info."
    echo ""
    exit 1
fi

if test "${OPENSSL}x" == "x" ; then
    echo "ERROR!  You must provide a valid path to openssl!"
    echo "\'$(basename ${0}) --help\' for more info."
    echo ""
    exit 1
fi

if test "${OUTFILE}x" == "x" ; then
    echo "ERROR!  You must provide a valid output file!"
    echo "\'$(basename ${0}) --help\' for more info."
    echo ""
    exit 1
fi

# Get on with the work

# If using a CAFILE, split it into individual files in a temp directory
if test "${CAFILE}x" != "x" ; then
    TEMPDIR=`mktemp -d`
    CADIR="${TEMPDIR}"

    # Get a list of staring lines for each cert
    CERTLIST=`grep -n "^-----BEGIN" "${CAFILE}" | cut -d ":" -f 1`

    # Get a list of ending lines for each cert
    ENDCERTLIST=`grep -n "^-----END" "${CAFILE}" | cut -d ":" -f 1`

    # Start a loop
    for certbegin in `echo "${CERTLIST}"` ; do
        for certend in `echo "${ENDCERTLIST}"` ; do
            if test "${certend}" -gt "${certbegin}"; then
                break
            fi
        done
        sed -n "${certbegin},${certend}p" "${CAFILE}" >
"${CADIR}/${certbegin}.pem"
        keyhash=`${OPENSSL} x509 -noout -in "${CADIR}/${certbegin}.pem"
-hash`
        echo "Generated PEM file with hash:  ${keyhash}."
    done
fi

# Write the output file
for cert in `find "${CADIR}" -type f -name "*.pem" -o -name "*.crt"`
do

    # Make sure the certificate date is valid...
    date=$( ${OPENSSL} x509 -enddate -in "${cert}" -noout | sed
's/^notAfter=//' )
    mydate "${date}"
    if test "${certdate}" -lt "${today}" ; then
        echo "${cert} expired on ${certdate}! Skipping..."
        unset date certdate
        continue
    fi
    unset date certdate
    ls "${cert}"
    tempfile=`mktemp`
    certbegin=`grep -n "^-----BEGIN" "${cert}" | cut -d ":" -f 1`
    certend=`grep -n "^-----END" "${cert}" | cut -d ":" -f 1`
    sed -n "${certbegin},${certend}p" "${cert}" > "${tempfile}"
    echo yes | env LC_ALL=C "${KEYTOOL}" -import -alias `basename
"${cert}"` -keystore \
                   "${OUTFILE}" -storepass 'changeit' -file "${tempfile}"
    rm "${tempfile}"
done

if test "${TEMPDIR}x" != "x" ; then
    rm -rf "${TEMPDIR}"
fi
exit 0

EOF
chmod -v 0755 mkcacerts.sh

5. Difference Between Original And New Scripts

$ diff -Naur mkcacerts-blfs-1.0.7.40-2.4.1.sh
mkcacerts-new-1.0.7.40-2.4.1.sh
--- mkcacerts-blfs-1.0.7.40-2.4.1.sh    2013-07-19 07:46:41.904926806 -0300
+++ mkcacerts-new-1.0.7.40-2.4.1.sh     2013-07-19 09:19:42.517727563 -0300
@@ -196,7 +196,7 @@
     certbegin=`grep -n "^-----BEGIN" "${cert}" | cut -d ":" -f 1`
     certend=`grep -n "^-----END" "${cert}" | cut -d ":" -f 1`
     sed -n "${certbegin},${certend}p" "${cert}" > "${tempfile}"
-    echo yes | "${KEYTOOL}" -import -alias `basename "${cert}"` -keystore \
+    echo yes | env LC_ALL=C "${KEYTOOL}" -import -alias `basename
"${cert}"` -keystore \
                    "${OUTFILE}" -storepass 'changeit' -file "${tempfile}"
     rm "${tempfile}"
 done

6. Difference Between Original And New Patches

$ diff -Naur icedtea-2.4.1-add_cacerts-1.patch
icedtea-2.4.1-add_cacerts-2.patch
--- icedtea-2.4.1-add_cacerts-1.patch   2013-07-18 05:20:05.000000000 -0300
+++ icedtea-2.4.1-add_cacerts-2.patch   2013-07-19 10:42:51.238359104 -0300
@@ -539,7 +539,7 @@
 +    certbegin=`grep -n "^-----BEGIN" "${cert}" | cut -d ":" -f 1`
 +    certend=`grep -n "^-----END" "${cert}" | cut -d ":" -f 1`
 +    sed -n "${certbegin},${certend}p" "${cert}" > "${tempfile}"
-+    echo yes | "${KEYTOOL}" -import -alias `basename "${cert}"`
-keystore \
++    echo yes | env LC_ALL=C "${KEYTOOL}" -import -alias `basename
"${cert}"` -keystore \
 +                   "${OUTFILE}" -storepass 'changeit' -file "${tempfile}"
 +    rm "${tempfile}"
 +done

-- 
[]s,
Fernando
-- 
http://linuxfromscratch.org/mailman/listinfo/blfs-dev
FAQ: http://www.linuxfromscratch.org/blfs/faq.html
Unsubscribe: See the above information page

Reply via email to