-----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-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to