< prev index next >

src/share/classes/sun/security/provider/JavaKeyStore.java

Print this page
rev 13649 : 8218553: Enhance keystore load debug output
Reviewed-by: weijun
   1 /*
   2  * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.security.provider;
  27 
  28 import java.io.*;
  29 import java.security.*;
  30 import java.security.cert.Certificate;
  31 import java.security.cert.CertificateFactory;
  32 import java.security.cert.CertificateException;
  33 import java.util.*;
  34 
  35 import sun.misc.IOUtils;
  36 import sun.security.pkcs.EncryptedPrivateKeyInfo;
  37 import sun.security.pkcs12.PKCS12KeyStore;

  38 
  39 /**
  40  * This class provides the keystore implementation referred to as "JKS".
  41  *
  42  * @author Jan Luehe
  43  * @author David Brownell
  44  *
  45  *
  46  * @see KeyProtector
  47  * @see java.security.KeyStoreSpi
  48  * @see KeyTool
  49  *
  50  * @since 1.2
  51  */
  52 
  53 abstract class JavaKeyStore extends KeyStoreSpi {
  54 
  55     // regular JKS
  56     public static final class JKS extends JavaKeyStore {
  57         String convertAlias(String alias) {
  58             return alias.toLowerCase(Locale.ENGLISH);
  59         }
  60     }
  61 
  62     // special JKS that uses case sensitive aliases
  63     public static final class CaseExactJKS extends JavaKeyStore {
  64         String convertAlias(String alias) {
  65             return alias;
  66         }
  67     }
  68 
  69     // special JKS that supports JKS and PKCS12 file formats
  70     public static final class DualFormatJKS extends KeyStoreDelegator {
  71         public DualFormatJKS() {
  72             super("JKS", JKS.class, "PKCS12", PKCS12KeyStore.class);
  73         }
  74     }
  75 

  76     private static final int MAGIC = 0xfeedfeed;
  77     private static final int VERSION_1 = 0x01;
  78     private static final int VERSION_2 = 0x02;
  79 
  80     // Private keys and their supporting certificate chains
  81     private static class KeyEntry {
  82         Date date; // the creation date of this entry
  83         byte[] protectedPrivKey;
  84         Certificate chain[];
  85     };
  86 
  87     // Trusted certificates
  88     private static class TrustedCertEntry {
  89         Date date; // the creation date of this entry
  90         Certificate cert;
  91     };
  92 
  93     /**
  94      * Private keys and certificates are stored in a hashtable.
  95      * Hash entries are keyed by alias names.


 625      * @param password the (optional) password used to check the integrity of
 626      * the keystore.
 627      *
 628      * @exception IOException if there is an I/O or format problem with the
 629      * keystore data
 630      * @exception NoSuchAlgorithmException if the algorithm used to check
 631      * the integrity of the keystore cannot be found
 632      * @exception CertificateException if any of the certificates in the
 633      * keystore could not be loaded
 634      */
 635     public void engineLoad(InputStream stream, char[] password)
 636         throws IOException, NoSuchAlgorithmException, CertificateException
 637     {
 638         synchronized(entries) {
 639             DataInputStream dis;
 640             MessageDigest md = null;
 641             CertificateFactory cf = null;
 642             Hashtable<String, CertificateFactory> cfs = null;
 643             ByteArrayInputStream bais = null;
 644             byte[] encoded = null;

 645 
 646             if (stream == null)
 647                 return;
 648 
 649             if (password != null) {
 650                 md = getPreKeyedHash(password);
 651                 dis = new DataInputStream(new DigestInputStream(stream, md));
 652             } else {
 653                 dis = new DataInputStream(stream);
 654             }
 655 
 656             // Body format: see store method
 657 
 658             int xMagic = dis.readInt();
 659             int xVersion = dis.readInt();
 660 
 661             if (xMagic!=MAGIC ||
 662                 (xVersion!=VERSION_1 && xVersion!=VERSION_2)) {
 663                 throw new IOException("Invalid keystore format");
 664             }
 665 
 666             if (xVersion == VERSION_1) {
 667                 cf = CertificateFactory.getInstance("X509");
 668             } else {
 669                 // version 2
 670                 cfs = new Hashtable<String, CertificateFactory>(3);
 671             }
 672 
 673             entries.clear();
 674             int count = dis.readInt();
 675 
 676             for (int i = 0; i < count; i++) {
 677                 int tag;
 678                 String alias;
 679 
 680                 tag = dis.readInt();
 681 
 682                 if (tag == 1) { // private key entry
 683 
 684                     KeyEntry entry = new KeyEntry();
 685 
 686                     // Read the alias
 687                     alias = dis.readUTF();
 688 
 689                     // Read the (entry creation) date
 690                     entry.date = new Date(dis.readLong());
 691 
 692                     // Read the private key
 693                     entry.protectedPrivKey =
 694                             IOUtils.readFully(dis, dis.readInt(), true);
 695 
 696                     // Read the certificate chain
 697                     int numOfCerts = dis.readInt();
 698                     if (numOfCerts > 0) {
 699                         List<Certificate> certs = new ArrayList<>(
 700                                 numOfCerts > 10 ? 10 : numOfCerts);
 701                         for (int j = 0; j < numOfCerts; j++) {
 702                             if (xVersion == 2) {
 703                                 // read the certificate type, and instantiate a


 712                                     cf = CertificateFactory.getInstance(certType);
 713                                     // store the certificate factory so we can
 714                                     // reuse it later
 715                                     cfs.put(certType, cf);
 716                                 }
 717                             }
 718                             // instantiate the certificate
 719                             encoded = IOUtils.readFully(dis, dis.readInt(), true);
 720                             bais = new ByteArrayInputStream(encoded);
 721                             certs.add(cf.generateCertificate(bais));
 722                             bais.close();
 723                         }
 724                         // We can be sure now that numOfCerts of certs are read
 725                         entry.chain = certs.toArray(new Certificate[numOfCerts]);
 726                     }
 727 
 728                     // Add the entry to the list
 729                     entries.put(alias, entry);
 730 
 731                 } else if (tag == 2) { // trusted certificate entry
 732 
 733                     TrustedCertEntry entry = new TrustedCertEntry();
 734 
 735                     // Read the alias
 736                     alias = dis.readUTF();
 737 
 738                     // Read the (entry creation) date
 739                     entry.date = new Date(dis.readLong());
 740 
 741                     // Read the trusted certificate
 742                     if (xVersion == 2) {
 743                         // read the certificate type, and instantiate a
 744                         // certificate factory of that type (reuse
 745                         // existing factory if possible)
 746                         String certType = dis.readUTF();
 747                         if (cfs.containsKey(certType)) {
 748                             // reuse certificate factory
 749                             cf = cfs.get(certType);
 750                         } else {
 751                             // create new certificate factory
 752                             cf = CertificateFactory.getInstance(certType);
 753                             // store the certificate factory so we can
 754                             // reuse it later
 755                             cfs.put(certType, cf);
 756                         }
 757                     }
 758                     encoded = IOUtils.readFully(dis, dis.readInt(), true);
 759                     bais = new ByteArrayInputStream(encoded);
 760                     entry.cert = cf.generateCertificate(bais);
 761                     bais.close();
 762 
 763                     // Add the entry to the list
 764                     entries.put(alias, entry);
 765 
 766                 } else {
 767                     throw new IOException("Unrecognized keystore entry");

 768                 }





 769             }
 770 
 771             /*
 772              * If a password has been provided, we check the keyed digest
 773              * at the end. If this check fails, the store has been tampered
 774              * with
 775              */
 776             if (password != null) {
 777                 byte computed[], actual[];
 778                 computed = md.digest();
 779                 actual = new byte[computed.length];
 780                 dis.readFully(actual);
 781                 for (int i = 0; i < computed.length; i++) {
 782                     if (computed[i] != actual[i]) {
 783                         Throwable t = new UnrecoverableKeyException
 784                             ("Password verification failed");
 785                         throw (IOException)new IOException
 786                             ("Keystore was tampered with, or "
 787                             + "password was incorrect").initCause(t);
 788                     }


   1 /*
   2  * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.security.provider;
  27 
  28 import java.io.*;
  29 import java.security.*;
  30 import java.security.cert.Certificate;
  31 import java.security.cert.CertificateFactory;
  32 import java.security.cert.CertificateException;
  33 import java.util.*;
  34 
  35 import sun.misc.IOUtils;
  36 import sun.security.pkcs.EncryptedPrivateKeyInfo;
  37 import sun.security.pkcs12.PKCS12KeyStore;
  38 import sun.security.util.Debug;
  39 
  40 /**
  41  * This class provides the keystore implementation referred to as "JKS".
  42  *
  43  * @author Jan Luehe
  44  * @author David Brownell
  45  *
  46  *
  47  * @see KeyProtector
  48  * @see java.security.KeyStoreSpi
  49  * @see KeyTool
  50  *
  51  * @since 1.2
  52  */
  53 
  54 abstract class JavaKeyStore extends KeyStoreSpi {
  55 
  56     // regular JKS
  57     public static final class JKS extends JavaKeyStore {
  58         String convertAlias(String alias) {
  59             return alias.toLowerCase(Locale.ENGLISH);
  60         }
  61     }
  62 
  63     // special JKS that uses case sensitive aliases
  64     public static final class CaseExactJKS extends JavaKeyStore {
  65         String convertAlias(String alias) {
  66             return alias;
  67         }
  68     }
  69 
  70     // special JKS that supports JKS and PKCS12 file formats
  71     public static final class DualFormatJKS extends KeyStoreDelegator {
  72         public DualFormatJKS() {
  73             super("JKS", JKS.class, "PKCS12", PKCS12KeyStore.class);
  74         }
  75     }
  76 
  77     private static final Debug debug = Debug.getInstance("keystore");
  78     private static final int MAGIC = 0xfeedfeed;
  79     private static final int VERSION_1 = 0x01;
  80     private static final int VERSION_2 = 0x02;
  81 
  82     // Private keys and their supporting certificate chains
  83     private static class KeyEntry {
  84         Date date; // the creation date of this entry
  85         byte[] protectedPrivKey;
  86         Certificate chain[];
  87     };
  88 
  89     // Trusted certificates
  90     private static class TrustedCertEntry {
  91         Date date; // the creation date of this entry
  92         Certificate cert;
  93     };
  94 
  95     /**
  96      * Private keys and certificates are stored in a hashtable.
  97      * Hash entries are keyed by alias names.


 627      * @param password the (optional) password used to check the integrity of
 628      * the keystore.
 629      *
 630      * @exception IOException if there is an I/O or format problem with the
 631      * keystore data
 632      * @exception NoSuchAlgorithmException if the algorithm used to check
 633      * the integrity of the keystore cannot be found
 634      * @exception CertificateException if any of the certificates in the
 635      * keystore could not be loaded
 636      */
 637     public void engineLoad(InputStream stream, char[] password)
 638         throws IOException, NoSuchAlgorithmException, CertificateException
 639     {
 640         synchronized(entries) {
 641             DataInputStream dis;
 642             MessageDigest md = null;
 643             CertificateFactory cf = null;
 644             Hashtable<String, CertificateFactory> cfs = null;
 645             ByteArrayInputStream bais = null;
 646             byte[] encoded = null;
 647             int trustedKeyCount = 0, privateKeyCount = 0;
 648 
 649             if (stream == null)
 650                 return;
 651 
 652             if (password != null) {
 653                 md = getPreKeyedHash(password);
 654                 dis = new DataInputStream(new DigestInputStream(stream, md));
 655             } else {
 656                 dis = new DataInputStream(stream);
 657             }
 658 
 659             // Body format: see store method
 660 
 661             int xMagic = dis.readInt();
 662             int xVersion = dis.readInt();
 663 
 664             if (xMagic!=MAGIC ||
 665                 (xVersion!=VERSION_1 && xVersion!=VERSION_2)) {
 666                 throw new IOException("Invalid keystore format");
 667             }
 668 
 669             if (xVersion == VERSION_1) {
 670                 cf = CertificateFactory.getInstance("X509");
 671             } else {
 672                 // version 2
 673                 cfs = new Hashtable<String, CertificateFactory>(3);
 674             }
 675 
 676             entries.clear();
 677             int count = dis.readInt();
 678 
 679             for (int i = 0; i < count; i++) {
 680                 int tag;
 681                 String alias;
 682 
 683                 tag = dis.readInt();
 684 
 685                 if (tag == 1) { // private key entry
 686                     privateKeyCount++;
 687                     KeyEntry entry = new KeyEntry();
 688 
 689                     // Read the alias
 690                     alias = dis.readUTF();
 691 
 692                     // Read the (entry creation) date
 693                     entry.date = new Date(dis.readLong());
 694 
 695                     // Read the private key
 696                     entry.protectedPrivKey =
 697                             IOUtils.readFully(dis, dis.readInt(), true);
 698 
 699                     // Read the certificate chain
 700                     int numOfCerts = dis.readInt();
 701                     if (numOfCerts > 0) {
 702                         List<Certificate> certs = new ArrayList<>(
 703                                 numOfCerts > 10 ? 10 : numOfCerts);
 704                         for (int j = 0; j < numOfCerts; j++) {
 705                             if (xVersion == 2) {
 706                                 // read the certificate type, and instantiate a


 715                                     cf = CertificateFactory.getInstance(certType);
 716                                     // store the certificate factory so we can
 717                                     // reuse it later
 718                                     cfs.put(certType, cf);
 719                                 }
 720                             }
 721                             // instantiate the certificate
 722                             encoded = IOUtils.readFully(dis, dis.readInt(), true);
 723                             bais = new ByteArrayInputStream(encoded);
 724                             certs.add(cf.generateCertificate(bais));
 725                             bais.close();
 726                         }
 727                         // We can be sure now that numOfCerts of certs are read
 728                         entry.chain = certs.toArray(new Certificate[numOfCerts]);
 729                     }
 730 
 731                     // Add the entry to the list
 732                     entries.put(alias, entry);
 733 
 734                 } else if (tag == 2) { // trusted certificate entry
 735                     trustedKeyCount++;
 736                     TrustedCertEntry entry = new TrustedCertEntry();
 737 
 738                     // Read the alias
 739                     alias = dis.readUTF();
 740 
 741                     // Read the (entry creation) date
 742                     entry.date = new Date(dis.readLong());
 743 
 744                     // Read the trusted certificate
 745                     if (xVersion == 2) {
 746                         // read the certificate type, and instantiate a
 747                         // certificate factory of that type (reuse
 748                         // existing factory if possible)
 749                         String certType = dis.readUTF();
 750                         if (cfs.containsKey(certType)) {
 751                             // reuse certificate factory
 752                             cf = cfs.get(certType);
 753                         } else {
 754                             // create new certificate factory
 755                             cf = CertificateFactory.getInstance(certType);
 756                             // store the certificate factory so we can
 757                             // reuse it later
 758                             cfs.put(certType, cf);
 759                         }
 760                     }
 761                     encoded = IOUtils.readFully(dis, dis.readInt(), true);
 762                     bais = new ByteArrayInputStream(encoded);
 763                     entry.cert = cf.generateCertificate(bais);
 764                     bais.close();
 765 
 766                     // Add the entry to the list
 767                     entries.put(alias, entry);
 768 
 769                 } else {
 770                     throw new IOException("Unrecognized keystore entry: " +
 771                             tag);
 772                 }
 773             }
 774 
 775             if (debug != null) {
 776                 debug.println("JavaKeyStore load: private key count: " +
 777                     privateKeyCount + ". trusted key count: " + trustedKeyCount);
 778             }
 779 
 780             /*
 781              * If a password has been provided, we check the keyed digest
 782              * at the end. If this check fails, the store has been tampered
 783              * with
 784              */
 785             if (password != null) {
 786                 byte computed[], actual[];
 787                 computed = md.digest();
 788                 actual = new byte[computed.length];
 789                 dis.readFully(actual);
 790                 for (int i = 0; i < computed.length; i++) {
 791                     if (computed[i] != actual[i]) {
 792                         Throwable t = new UnrecoverableKeyException
 793                             ("Password verification failed");
 794                         throw (IOException)new IOException
 795                             ("Keystore was tampered with, or "
 796                             + "password was incorrect").initCause(t);
 797                     }


< prev index next >