Mantis Bugtracker
  

Viewing Issue Simple Details Jump to Notes ] View Advanced ] Issue History ] Print ]
ID Category Severity Reproducibility Date Submitted Last Update
0001333 [Resin] minor always 09-09-06 09:13 09-13-06 15:29
Reporter ajaquith2 View Status public  
Assigned To ferg
Priority normal Resolution fixed  
Status closed   Product Version 3.0.22
Summary 0001333: Re-opening issue 1008: Problems running jspwiki
Description A JSPWiki user reported a bug in Resin that was preventing JSPWiki 2.4.x from working. After investigation, I determined that the problem related to Resin's treatment of JAR certificates. Although the bug has been marked fixed and closed as of 3.0.22, it is not actually fixed yet.
Additional Information According to the bug report, the issue has been fixed as of 3.0.22, and I have verified that some of my code recommentations were implemented.

See: http://bugs.caucho.com/bug_view_advanced_page.php?bug_id=1008 [^]

The problem was not actually fixed, however.

The good news: com.caucho.vfs.JarPath now includes a Certificate[] getCerticates() method. Likewise, this method is backed by a new com.caucho.vfs.Jar method called Certificate[] getCertificates(String path). Lovely.

However, the current fix contains two bugs, which compound each other.

First, JarPath.getCertifcates() is not actually called by com.caucho.loader.JarEntry, specifically in the class constructor, as it should be.

Here's what the code looks like now, in current (tonight's) builds:

  JarEntry(JarPath jarPath)
  {
    _jarPath = jarPath;

    try {
      _codeSource = new CodeSource(new URL(jarPath.getURL()),
                   (Certificate []) null);
    } catch (Exception e) {
      log.log(Level.WARNING, e.toString(), e);
    }

    readManifest();
  }

The 5th line of the method should, instead, look like this:

      _codeSource = new CodeSource(new URL(jarPath.getURL()),
                   (Certificate []) jarPath.getCertificates());

The second error is related to com.caucho.resin.vfs.Jar.getCertificates(String path), which does not return certificates if the JAR path supplied to the method is the root path ("/"). Here is the relevant code in the Jar class (lines 224+):

 public Certificate []getCertificates(String path)
  {
    if (path.length() > 0 && path.charAt(0) == '/')
      path = path.substring(1);

    try {
      JarFile jarFile = new JarFile(_backing.getNativePath());
      JarEntry entry;
      InputStream is = null;

      try {
    entry = (JarEntry) jarFile.getEntry(path);
      
    if (entry != null) {
      is = jarFile.getInputStream(entry);

      while (is.skip(65536) > 0) {
      }

      is.close();

      return entry.getCertificates();

Notice the what happens to 'path' if it set to the root path, which would be the case when we load the JAR for the first time as a whole. If 'path' is root (/), it is truncated to "", and the jarFile.getEntry(path) line *always* returns null, which means we never get to read certificates. That means that the Java core security classes (e.g., Policy, PolicyFile, ProtectionDomain et al) will never know that a JAR as a whole might be signed.

Here's a version of the Jar.getCertificates(String) method that works. It's not particularly efficient, but it does do what we want, namely return the certificate array for those cases where the path is the root, and also return the correct certificates for specific paths inside the JAR:

  /**
   * Returns any certificates.
   */
  public Certificate []getCertificates(String path)
  {
    if (path.length() > 0 && path.charAt(0) == '/')
      path = path.substring(1);
      
    ArrayList certs = new ArrayList();

    try {
      JarFile jarFile = new JarFile(_backing.getNativePath());
      if ("".equals(path))
      {
        // Retrieve all certificates that signed anything in this JAR
        Enumeration entries = jarFile.entries();
        while( entries.hasMoreElements() )
        {
          JarEntry entry = (JarEntry) entries.nextElement();
          Certificate[] signers = extractCertificates(jarFile, entry);
          for( int i = 0; i < signers.length; i++ )
          {
              Certificate signer = signers[i];
              if ( signer instanceof X509Certificate && !certs.contains( signer ) )
              {
                  certs.add( signer );
              }
          }
        }
      }
      else
      {
        // Get the certificates that signed this entry
        JarEntry entry = (JarEntry) jarFile.getEntry(path);
        Certificate[] signers = extractCertificates(jarFile, entry);
        for( int i = 0; i < signers.length; i++ )
        {
            Certificate signer = signers[i];
            if ( signer instanceof X509Certificate && !certs.contains( signer ) )
            {
                certs.add( signer );
            }
        }
      }
    } catch (IOException e) {
      log.log(Level.FINE, e.toString(), e);
    }
    if (certs.size() > 0) {
      return (Certificate[])certs.toArray(new X509Certificate[certs.size()]);
    }
    return null;
  }
  
  /**
   * Extracts the certificates for a supplied JarEntry.
   */
  private Certificate[] extractCertificates(JarFile jarFile, JarEntry entry)
  {
    InputStream is = null;
    try {
      is = jarFile.getInputStream( entry );
      while (is.skip(65536) > 0) { /* Read the entry */ }
      is.close();
      Certificate[] certs = entry.getCertificates();
      if (certs != null) {
        return certs;
      }
    } catch (IOException e) {
      log.log(Level.FINE, e.toString(), e);
    }
    return new X509Certificate[0];
  }

If the path is the root path ("" or "/"), this will return *all* certificates used to sign *any* classes in the JAR. This is a hack, but a reasonable one. But if the path is for something inside the JAR, it will return the certificates used to sign just that element.

I've tested this with JSPWiki 2.4.41, and it works as advertised.
Attached Files

- Relationships

- Notes
(0001514)
ferg
09-13-06 15:29

Fixed in a slightly different way, creating separate CodeSources for each entry.
 

- Issue History
Date Modified Username Field Change
09-09-06 09:13 ajaquith2 New Issue
09-13-06 15:29 ferg Note Added: 0001514
09-13-06 15:29 ferg Assigned To  => ferg
09-13-06 15:29 ferg Status new => closed
09-13-06 15:29 ferg Resolution open => fixed


Mantis 1.0.0rc3[^]
Copyright © 2000 - 2005 Mantis Group
29 total queries executed.
26 unique queries executed.
Powered by Mantis Bugtracker