You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by Christopher Schultz <ch...@christopherschultz.net> on 2020/06/12 21:54:00 UTC

Java library bug in JCEKS keystore loader

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

All,

I've been writing a Java-based certification-expiration checking
utility that can handle all kinds of file formats like PEM and the
various keystore formats supported by the JVM.

Since it's not possible to tell what type of keystore is being loaded
without writing a bunch of magic-checking code or implementing an
ASN.1 parser (no thank you), I simply try all keystore types until I
find one that works. I'm using a rewindable InputStream which works well
.

Until you try to use the JCEKS keystore loader, specifically in Java
versions 8 - 13. I haven't checked that later versions, and it appears
that it's been fixed in Java 14.

The API call is KeyStore.load(InputStream, char[]) and usually it
behaves well. Unfortunately, in these affected versions, the JCEKS
provider (which happens to be com.sun.crypto.provider.JceKeyStore, in
the public engineLoad method) calls InputStream.close on the stream
passed-into it. Yuck.

JCEKS is a little-used keystore format, but it is required to store
secret keys (different from private keys) because JKS can't support
those. So it's possible that some users have been forced to use JCEKS
keystore format.

I haven't looked-through the Tomcat code yet to see if there could be
places where this could cause a problem. Sane code usually looks like
this:

try(FileInputStream fin = new FileInputStream("keystore.jceks")) {
  KeyStore ks = KeyStore.getInstance("JCEKS");
  ks.load(fin);
}

This code will fail with "java.io.IOException: Stream closed", which
is of course incorrect resource management.

My solution was to simply wrap the InputStream in one that will simply
ignore any attempts to close it:

try(FileInputStream fin = new UnclosableInputStream(new
FileInputStream("keystore.jceks"))) {
  KeyStore ks = KeyStore.getInstance("JCEKS");
  ks.load(fin);
}

    public class UnclosableInputStream
         extends java.io.FilterInputStream
    {
        protected UnclosableInputStream(InputStream in) {
            super(in);
        }

        @Override
        public void close() throws IOException
        {
            // System.out.println("DEBUG: Ignoring attempt to close
InputStream by provider of keystore type " + keystoreType);
            // new Throwable("trace").printStackTrace();
        }
    }

I'll be looking at Tomcat's keystore-loading code to see if this would
be helpful, as not many people are running Tomcat on Java 14 yet, I
would guess.

- -chris

P.S. I'll probably be releasing this tool on GitHub, soon, if anyone
wants to have a look.
-----BEGIN PGP SIGNATURE-----
Comment: Using GnuPG with Thunderbird - https://www.enigmail.net/

iQIzBAEBCAAdFiEEMmKgYcQvxMe7tcJcHPApP6U8pFgFAl7j+XgACgkQHPApP6U8
pFgUPQ/+L7DQhP19ELBKYUbXQgdKN+aieiJoQap5wID+QZSXBJmbEgnUvrRcLdte
oBaTgOJc3pKc6lV2K6PYIzT2HTpB4420h9cbn6vtFAuTdbN08RTxO5e6IGBUovtT
o/Y0iVSy4m3aQfOg7nISqGoaVggDffTrr/ZQDPgjxbTbAeTHEhk7eCN0nNMWmzFD
V2jn7b7IOowZoXRSWlMZ4FqmjPIugckmIs1qDfzooPQhdplLpbJn1ucLikG/j5jj
kmeCRaiPtNCC3FmhlBgkU5Ac50LksoY4uR0dROzpxyZbClyUnq2zAIY/9paygG8s
ZK/FZIaTdzJU3VeemaE3mMuCIDtTwzmRJH29kMTz1X4GOvsL3PbHFqeav9KGmUWO
H3ASkTe27jhXSzxLrbxIsaQDRTAjscMMBAjy11Nsp5Qism7JQ7OgKiX0nOnR2Vne
hP7cgk9snAkI9QhnTnyqnSd7dYKjMqEmmIa58YuRc+OaUeNf3wwmljSpKYvI2D31
ldBCEVF4PE+GNT0DXGfX2osTLMkglkDkgElHWennTDkHko72aexNX7c3Ut3+ldRu
ho6CG2Fwaugw/QS3uk9E/ZfXwl5ZU2Rn4ysWac17FHgOA7A/yHrPkJxDxKGZHSHI
rzMgeyquIpizAJEj6NKNQJdwujcZeVAhvUae+mQyoaJYplEpKRs=
=AakA
-----END PGP SIGNATURE-----

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


Re: Java library bug in JCEKS keystore loader

Posted by Christopher Schultz <ch...@christopherschultz.net>.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Michael,

On 6/13/20 14:54, Michael Osipov wrote:
> Am 2020-06-12 um 23:54 schrieb Christopher Schultz:
>> -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA256
>>
>> All,
>>
>> I've been writing a Java-based certification-expiration checking
>> utility that can handle all kinds of file formats like PEM and
>> the various keystore formats supported by the JVM.
>>
>> Since it's not possible to tell what type of keystore is being
>> loaded without writing a bunch of magic-checking code or
>> implementing an ASN.1 parser (no thank you), I simply try all
>> keystore types until I find one that works. I'm using a
>> rewindable InputStream which works well .
>
> there is no need to, use Apache Directory Kerby ASN.1 module. I use
> it too and it works very well for my certiticate tasks at work.

It's pretty simple to look for "-----BEGIN" or hand-off things to
KeyStore.load. Right now, this is a single-class utility with no
dependencies. No need to add more dependencies if they aren't
necessary. I'm not looking to build a complete certificate
manipulation framework.

Attempting to load using KeyStore.load will be required, anyway, for
keystore types such as JKS, JCEKS, Windows-MY, Windows-ROOT,
KeychainStore, etc. which aren't ASN.1 files like PKCS12.

Anyway, the point was that there is a bug in one of the keystore
implementations that may cause some troubles.

Thanks,
- -chris
-----BEGIN PGP SIGNATURE-----
Comment: Using GnuPG with Thunderbird - https://www.enigmail.net/

iQIzBAEBCAAdFiEEMmKgYcQvxMe7tcJcHPApP6U8pFgFAl7o4iMACgkQHPApP6U8
pFiiiQ/+I2UHDRSi2xqP1ehQIBvwMXDxtXq71nCeZrN6VTEyPJS3V1IqJVKG4eks
9rAc7QnVYBMSaWglzVJQKKl8zdf8GncOYhk8JkDEON7LjLDuyLRj2m/bHkivQs6Q
AY/Fo9CRSscxV1YS78erNdMDLwWr7YXmkeJypJ1IL8OaB5kNzIak3t70zb3XRSWb
3JQ4F/64AYv+nnapGbsT2pYTMy6vKOVTearrXKZQJGRD0NIbz7xAh/tceem4eeUh
SGQLPJW6Bg1fN52bmKOuluCCu95K8u2eblqoPVlTvtJutxGDSz2HGCjJLISqgJrZ
PvwIpsbpCQ8x1vOXL4geu0XhXmpEtA49s3sj8c0aFUM2Aq9z4kRfQz0/BQQaeZo4
r1inQ4CSj2dhtE/7lGtMG4aXjoJgtvC81rcJR/rrr2VjZwQOWSHmcPVWKAG0Pk00
NffUll3+BcZnFbeMzV/GkMonY7bXfHvDkvlwjdA8ykAWAYXUy4fsQoHwU+RiODLh
ds7OwjtA6WlJMPvWprZXucmhEAXDBJJsU55ttEtIeDMf3NU6j9ckHwDvzg9M1BcW
2rPgZyOoZiz9vwsjRyEXp7V/luMZI7KnbTpa/l/DkU+ET5284B/zy95V3/CU8HgD
oYY5D/PtEdE6S4Y34whpcb7dUffKoFIMDVaDXGbcaA8D5VwRi1g=
=0dZ2
-----END PGP SIGNATURE-----

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


Re: Java library bug in JCEKS keystore loader

Posted by Michael Osipov <mi...@apache.org>.
Am 2020-06-12 um 23:54 schrieb Christopher Schultz:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA256
> 
> All,
> 
> I've been writing a Java-based certification-expiration checking
> utility that can handle all kinds of file formats like PEM and the
> various keystore formats supported by the JVM.
> 
> Since it's not possible to tell what type of keystore is being loaded
> without writing a bunch of magic-checking code or implementing an
> ASN.1 parser (no thank you), I simply try all keystore types until I
> find one that works. I'm using a rewindable InputStream which works well
> .

there is no need to, use Apache Directory Kerby ASN.1 module. I use it 
too and it works very well for my certiticate tasks at work.

Michael

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org