jdk/src/share/classes/sun/security/util/SignatureFileVerifier.java
changeset 9365 469cd39a25de
parent 9248 44d129a2adfa
child 10336 0bb1999251f8
equal deleted inserted replaced
9307:f4298bc3f4b6 9365:469cd39a25de
    53         (Locale.ENGLISH);
    53         (Locale.ENGLISH);
    54 
    54 
    55     /** the PKCS7 block for this .DSA/.RSA/.EC file */
    55     /** the PKCS7 block for this .DSA/.RSA/.EC file */
    56     private PKCS7 block;
    56     private PKCS7 block;
    57 
    57 
    58     // the content of the raw .SF file as an InputStream
    58     /** the raw bytes of the .SF file */
    59     private InputStream sfStream;
    59     private byte sfBytes[];
    60 
    60 
    61     /** the name of the signature block file, uppercased and without
    61     /** the name of the signature block file, uppercased and without
    62      *  the extension (.DSA/.RSA/.EC)
    62      *  the extension (.DSA/.RSA/.EC)
    63      */
    63      */
    64     private String name;
    64     private String name;
    65 
    65 
    66     /** the ManifestDigester */
    66     /** the ManifestDigester */
    67     private ManifestDigester md;
    67     private ManifestDigester md;
    68 
    68 
    69     /** The MANIFEST.MF */
       
    70     private Manifest man;
       
    71 
       
    72     /** cache of created MessageDigest objects */
    69     /** cache of created MessageDigest objects */
    73     private HashMap<String, MessageDigest> createdDigests;
    70     private HashMap<String, MessageDigest> createdDigests;
    74 
    71 
    75     /* workaround for parsing Netscape jars  */
    72     /* workaround for parsing Netscape jars  */
    76     private boolean workaround = false;
    73     private boolean workaround = false;
    84      * @param name the name of the signature block file (.DSA/.RSA/.EC)
    81      * @param name the name of the signature block file (.DSA/.RSA/.EC)
    85      *
    82      *
    86      * @param rawBytes the raw bytes of the signature block file
    83      * @param rawBytes the raw bytes of the signature block file
    87      */
    84      */
    88     public SignatureFileVerifier(ArrayList<CodeSigner[]> signerCache,
    85     public SignatureFileVerifier(ArrayList<CodeSigner[]> signerCache,
    89                                  Manifest man,
       
    90                                  ManifestDigester md,
    86                                  ManifestDigester md,
    91                                  String name,
    87                                  String name,
    92                                  byte rawBytes[])
    88                                  byte rawBytes[])
    93         throws IOException, CertificateException
    89         throws IOException, CertificateException
    94     {
    90     {
    96         // need to use local providers here, see Providers class
    92         // need to use local providers here, see Providers class
    97         Object obj = null;
    93         Object obj = null;
    98         try {
    94         try {
    99             obj = Providers.startJarVerification();
    95             obj = Providers.startJarVerification();
   100             block = new PKCS7(rawBytes);
    96             block = new PKCS7(rawBytes);
   101             byte[] contentData = block.getContentInfo().getData();
    97             sfBytes = block.getContentInfo().getData();
   102             if (contentData != null) {
       
   103                 sfStream = new ByteArrayInputStream(contentData);
       
   104             }
       
   105             certificateFactory = CertificateFactory.getInstance("X509");
    98             certificateFactory = CertificateFactory.getInstance("X509");
   106         } finally {
    99         } finally {
   107             Providers.stopJarVerification(obj);
   100             Providers.stopJarVerification(obj);
   108         }
   101         }
   109         this.name = name.substring(0, name.lastIndexOf("."))
   102         this.name = name.substring(0, name.lastIndexOf("."))
   110                                                    .toUpperCase(Locale.ENGLISH);
   103                                                    .toUpperCase(Locale.ENGLISH);
   111 
       
   112         this.man = man;
       
   113         this.md = md;
   104         this.md = md;
   114         this.signerCache = signerCache;
   105         this.signerCache = signerCache;
   115     }
   106     }
   116 
   107 
   117     /**
   108     /**
   118      * returns true if we need the .SF file
   109      * returns true if we need the .SF file
   119      */
   110      */
   120     public boolean needSignatureFile()
   111     public boolean needSignatureFileBytes()
   121     {
   112     {
   122         return sfStream == null;
   113 
   123     }
   114         return sfBytes == null;
   124 
   115     }
   125     public void setSignatureFile(InputStream ins) {
   116 
   126         this.sfStream = ins;
   117 
       
   118     /**
       
   119      * returns true if we need this .SF file.
       
   120      *
       
   121      * @param name the name of the .SF file without the extension
       
   122      *
       
   123      */
       
   124     public boolean needSignatureFile(String name)
       
   125     {
       
   126         return this.name.equalsIgnoreCase(name);
       
   127     }
       
   128 
       
   129     /**
       
   130      * used to set the raw bytes of the .SF file when it
       
   131      * is external to the signature block file.
       
   132      */
       
   133     public void setSignatureFile(byte sfBytes[])
       
   134     {
       
   135         this.sfBytes = sfBytes;
   127     }
   136     }
   128 
   137 
   129     /**
   138     /**
   130      * Utility method used by JarVerifier and JarSigner
   139      * Utility method used by JarVerifier and JarSigner
   131      * to determine the signature file names and PKCS7 block
   140      * to determine the signature file names and PKCS7 block
   134      * @param s file name
   143      * @param s file name
   135      * @return true if the input file name is a supported
   144      * @return true if the input file name is a supported
   136      *          Signature File or PKCS7 block file name
   145      *          Signature File or PKCS7 block file name
   137      */
   146      */
   138     public static boolean isBlockOrSF(String s) {
   147     public static boolean isBlockOrSF(String s) {
   139         return s.endsWith(".SF") || isBlock(s);
   148         // we currently only support DSA and RSA PKCS7 blocks
   140     }
   149         if (s.endsWith(".SF") || s.endsWith(".DSA") ||
   141 
   150                 s.endsWith(".RSA") || s.endsWith(".EC")) {
   142     /**
   151             return true;
   143      * Utility method used by JarVerifier to determine PKCS7 block
   152         }
   144      * files names that are supported
   153         return false;
   145      *
       
   146      * @param s file name
       
   147      * @return true if the input file name is a PKCS7 block file name
       
   148      */
       
   149     public static boolean isBlock(String s) {
       
   150         return s.endsWith(".DSA") || s.endsWith(".RSA") || s.endsWith(".EC");
       
   151     }
   154     }
   152 
   155 
   153     /** get digest from cache */
   156     /** get digest from cache */
   154 
   157 
   155     private MessageDigest getDigest(String algorithm)
   158     private MessageDigest getDigest(String algorithm)
   175      * and adds code signers for each section where the .SF section
   178      * and adds code signers for each section where the .SF section
   176      * hash was verified against the Manifest section.
   179      * hash was verified against the Manifest section.
   177      *
   180      *
   178      *
   181      *
   179      */
   182      */
   180     public void process(Map<String, CodeSigner[]> signers,
   183     public void process(Hashtable<String, CodeSigner[]> signers,
   181             List manifestDigests)
   184             List manifestDigests)
   182         throws IOException, SignatureException, NoSuchAlgorithmException,
   185         throws IOException, SignatureException, NoSuchAlgorithmException,
   183             JarException, CertificateException
   186             JarException, CertificateException
   184     {
   187     {
   185         // calls Signature.getInstance() and MessageDigest.getInstance()
   188         // calls Signature.getInstance() and MessageDigest.getInstance()
   192             Providers.stopJarVerification(obj);
   195             Providers.stopJarVerification(obj);
   193         }
   196         }
   194 
   197 
   195     }
   198     }
   196 
   199 
   197     private void processImpl(Map<String, CodeSigner[]> signers,
   200     private void processImpl(Hashtable<String, CodeSigner[]> signers,
   198             List manifestDigests)
   201             List manifestDigests)
   199         throws IOException, SignatureException, NoSuchAlgorithmException,
   202         throws IOException, SignatureException, NoSuchAlgorithmException,
   200             JarException, CertificateException
   203             JarException, CertificateException
   201     {
   204     {
   202         SignatureFileManifest sf = new SignatureFileManifest();
   205         Manifest sf = new Manifest();
   203         InputStream ins = sfStream;
   206         sf.read(new ByteArrayInputStream(sfBytes));
   204 
   207 
   205         byte[] buffer = new byte[4096];
   208         String version =
   206         int sLen = block.getSignerInfos().length;
   209             sf.getMainAttributes().getValue(Attributes.Name.SIGNATURE_VERSION);
   207         boolean mainOK = false;         // main attributes of SF is available...
   210 
   208         boolean manifestSigned = false; // and it matches MANIFEST.MF
   211         if ((version == null) || !(version.equalsIgnoreCase("1.0"))) {
   209         BASE64Decoder decoder = new BASE64Decoder();
   212             // XXX: should this be an exception?
   210 
   213             // for now we just ignore this signature file
   211         PKCS7.PKCS7Verifier[] pvs = new PKCS7.PKCS7Verifier[sLen];
   214             return;
   212         for (int i=0; i<sLen; i++) {
   215         }
   213             pvs[i] = PKCS7.PKCS7Verifier.from(block, block.getSignerInfos()[i]);
   216 
   214         }
   217         SignerInfo[] infos = block.verify(sfBytes);
   215 
   218 
   216         /*
   219         if (infos == null) {
   217          * Verify SF in streaming mode. The chunks of the file are fed into
       
   218          * the Manifest object sf and all PKCS7Verifiers. As soon as the main
       
   219          * attributes is available, we'll check if manifestSigned is true. If
       
   220          * yes, there is no need to fill in sf's entries field, since it should
       
   221          * be identical to entries in man.
       
   222          */
       
   223         while (true) {
       
   224             int len = ins.read(buffer);
       
   225             if (len < 0) {
       
   226                 if (!manifestSigned) {
       
   227                     sf.update(null, 0, 0);
       
   228                 }
       
   229                 break;
       
   230             } else {
       
   231                 for (int i=0; i<sLen; i++) {
       
   232                     if (pvs[i] != null) pvs[i].update(buffer, 0, len);
       
   233                 }
       
   234                 // Continue reading if verifyManifestHash fails (or, the
       
   235                 // main attributes is not available yet)
       
   236                 if (!manifestSigned) {
       
   237                     sf.update(buffer, 0, len);
       
   238                     if (!mainOK) {
       
   239                         try {
       
   240                             Attributes attr = sf.getMainAttributes();
       
   241                             String version = attr.getValue(
       
   242                                     Attributes.Name.SIGNATURE_VERSION);
       
   243 
       
   244                             if ((version == null) ||
       
   245                                     !(version.equalsIgnoreCase("1.0"))) {
       
   246                                 // XXX: should this be an exception?
       
   247                                 // for now we just ignore this signature file
       
   248                                 return;
       
   249                             }
       
   250 
       
   251                             mainOK = true;
       
   252                             manifestSigned = verifyManifestHash(
       
   253                                     sf, md, decoder, manifestDigests);
       
   254                         } catch (IllegalStateException ise) {
       
   255                             // main attributes not available yet
       
   256                         }
       
   257                     }
       
   258                 }
       
   259             }
       
   260         }
       
   261         List<SignerInfo> intResult = new ArrayList<>(sLen);
       
   262         for (int i = 0; i < sLen; i++) {
       
   263             if (pvs[i] != null) {
       
   264                 SignerInfo signerInfo = pvs[i].verify();
       
   265                 if (signerInfo != null) {
       
   266                     intResult.add(signerInfo);
       
   267                 }
       
   268             }
       
   269         }
       
   270         if (intResult.isEmpty()) {
       
   271             throw new SecurityException("cannot verify signature block file " +
   220             throw new SecurityException("cannot verify signature block file " +
   272                                         name);
   221                                         name);
   273         }
   222         }
   274 
   223 
   275         SignerInfo[] infos =
   224         BASE64Decoder decoder = new BASE64Decoder();
   276                 intResult.toArray(new SignerInfo[intResult.size()]);
       
   277 
   225 
   278         CodeSigner[] newSigners = getSigners(infos, block);
   226         CodeSigner[] newSigners = getSigners(infos, block);
   279 
   227 
   280         // make sure we have something to do all this work for...
   228         // make sure we have something to do all this work for...
   281         if (newSigners == null)
   229         if (newSigners == null)
   282             return;
   230             return;
       
   231 
       
   232         Iterator<Map.Entry<String,Attributes>> entries =
       
   233                                 sf.getEntries().entrySet().iterator();
       
   234 
       
   235         // see if we can verify the whole manifest first
       
   236         boolean manifestSigned = verifyManifestHash(sf, md, decoder, manifestDigests);
   283 
   237 
   284         // verify manifest main attributes
   238         // verify manifest main attributes
   285         if (!manifestSigned && !verifyManifestMainAttrs(sf, md, decoder)) {
   239         if (!manifestSigned && !verifyManifestMainAttrs(sf, md, decoder)) {
   286             throw new SecurityException
   240             throw new SecurityException
   287                 ("Invalid signature file digest for Manifest main attributes");
   241                 ("Invalid signature file digest for Manifest main attributes");
   288         }
   242         }
   289 
   243 
   290         Iterator<Map.Entry<String,Attributes>> entries;
   244         // go through each section in the signature file
   291 
       
   292         if (manifestSigned) {
       
   293             if (debug != null) {
       
   294                 debug.println("full manifest signature match, "
       
   295                         + "update signer info from MANIFEST.MF");
       
   296             }
       
   297             entries = man.getEntries().entrySet().iterator();
       
   298         } else {
       
   299             if (debug != null) {
       
   300                 debug.println("full manifest signature unmatch, "
       
   301                         + "update signer info from SF file");
       
   302             }
       
   303             entries = sf.getEntries().entrySet().iterator();
       
   304         }
       
   305 
       
   306         // go through each section
       
   307 
       
   308         while(entries.hasNext()) {
   245         while(entries.hasNext()) {
   309 
   246 
   310             Map.Entry<String,Attributes> e = entries.next();
   247             Map.Entry<String,Attributes> e = entries.next();
   311             String name = e.getKey();
   248             String name = e.getKey();
   312 
   249 
   313             if (manifestSigned ||
   250             if (manifestSigned ||
   314                     (verifySection(e.getValue(), name, md, decoder))) {
   251                 (verifySection(e.getValue(), name, md, decoder))) {
   315 
   252 
   316                 if (name.startsWith("./"))
   253                 if (name.startsWith("./"))
   317                     name = name.substring(2);
   254                     name = name.substring(2);
   318 
   255 
   319                 if (name.startsWith("/"))
   256                 if (name.startsWith("/"))
   654     {
   591     {
   655         // check for the same object
   592         // check for the same object
   656         if (set == subset)
   593         if (set == subset)
   657             return true;
   594             return true;
   658 
   595 
       
   596         boolean match;
   659         for (int i = 0; i < subset.length; i++) {
   597         for (int i = 0; i < subset.length; i++) {
   660             if (!contains(set, subset[i]))
   598             if (!contains(set, subset[i]))
   661                 return false;
   599                 return false;
   662         }
   600         }
   663         return true;
   601         return true;
   672         CodeSigner[] newSigners) {
   610         CodeSigner[] newSigners) {
   673 
   611 
   674         // special case
   612         // special case
   675         if ((oldSigners == null) && (signers == newSigners))
   613         if ((oldSigners == null) && (signers == newSigners))
   676             return true;
   614             return true;
       
   615 
       
   616         boolean match;
   677 
   617 
   678         // make sure all oldSigners are in signers
   618         // make sure all oldSigners are in signers
   679         if ((oldSigners != null) && !isSubSet(oldSigners, signers))
   619         if ((oldSigners != null) && !isSubSet(oldSigners, signers))
   680             return false;
   620             return false;
   681 
   621 
   696         }
   636         }
   697         return true;
   637         return true;
   698     }
   638     }
   699 
   639 
   700     void updateSigners(CodeSigner[] newSigners,
   640     void updateSigners(CodeSigner[] newSigners,
   701         Map<String, CodeSigner[]> signers, String name) {
   641         Hashtable<String, CodeSigner[]> signers, String name) {
   702 
   642 
   703         CodeSigner[] oldSigners = signers.get(name);
   643         CodeSigner[] oldSigners = signers.get(name);
   704 
   644 
   705         // search through the cache for a match, go in reverse order
   645         // search through the cache for a match, go in reverse order
   706         // as we are more likely to find a match with the last one
   646         // as we are more likely to find a match with the last one