mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			307 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			307 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Java
		
	
	
	
/* X509CertPath.java -- an X.509 certificate path.
 | 
						|
   Copyright (C) 2004  Free Software Fonudation, Inc.
 | 
						|
 | 
						|
This file is part of GNU Classpath.
 | 
						|
 | 
						|
GNU Classpath is free software; you can redistribute it and/or modify
 | 
						|
it under the terms of the GNU General Public License as published by
 | 
						|
the Free Software Foundation; either version 2, or (at your option)
 | 
						|
any later version.
 | 
						|
 | 
						|
GNU Classpath is distributed in the hope that it will be useful, but
 | 
						|
WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
						|
General Public License for more details.
 | 
						|
 | 
						|
You should have received a copy of the GNU General Public License
 | 
						|
along with GNU Classpath; see the file COPYING.  If not, write to the
 | 
						|
Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
 | 
						|
02111-1307 USA.
 | 
						|
 | 
						|
Linking this library statically or dynamically with other modules is
 | 
						|
making a combined work based on this library.  Thus, the terms and
 | 
						|
conditions of the GNU General Public License cover the whole
 | 
						|
combination.
 | 
						|
 | 
						|
As a special exception, the copyright holders of this library give you
 | 
						|
permission to link this library with independent modules to produce an
 | 
						|
executable, regardless of the license terms of these independent
 | 
						|
modules, and to copy and distribute the resulting executable under
 | 
						|
terms of your choice, provided that you also meet, for each linked
 | 
						|
independent module, the terms and conditions of the license of that
 | 
						|
module.  An independent module is a module which is not derived from
 | 
						|
or based on this library.  If you modify this library, you may extend
 | 
						|
this exception to your version of the library, but you are not
 | 
						|
obligated to do so.  If you do not wish to do so, delete this
 | 
						|
exception statement from your version. */
 | 
						|
 | 
						|
 | 
						|
package gnu.java.security.x509;
 | 
						|
 | 
						|
import java.io.ByteArrayInputStream;
 | 
						|
import java.io.ByteArrayOutputStream;
 | 
						|
import java.io.InputStream;
 | 
						|
import java.io.IOException;
 | 
						|
 | 
						|
import java.math.BigInteger;
 | 
						|
 | 
						|
import java.security.cert.Certificate;
 | 
						|
import java.security.cert.CertificateEncodingException;
 | 
						|
import java.security.cert.CertificateException;
 | 
						|
import java.security.cert.CertPath;
 | 
						|
 | 
						|
import java.util.ArrayList;
 | 
						|
import java.util.Arrays;
 | 
						|
import java.util.Collections;
 | 
						|
import java.util.Iterator;
 | 
						|
import java.util.LinkedList;
 | 
						|
import java.util.List;
 | 
						|
 | 
						|
import gnu.java.security.OID;
 | 
						|
import gnu.java.security.der.DER;
 | 
						|
import gnu.java.security.der.DEREncodingException;
 | 
						|
import gnu.java.security.der.DERReader;
 | 
						|
import gnu.java.security.der.DERValue;
 | 
						|
 | 
						|
/**
 | 
						|
 * A certificate path (or certificate chain) of X509Certificates.
 | 
						|
 *
 | 
						|
 * @author Casey Marshall (rsdio@metastatic.org)
 | 
						|
 */
 | 
						|
public class X509CertPath extends CertPath
 | 
						|
{
 | 
						|
 | 
						|
  // Fields.
 | 
						|
  // -------------------------------------------------------------------------
 | 
						|
 | 
						|
  public static final List ENCODINGS = Collections.unmodifiableList(
 | 
						|
    Arrays.asList(new String[] { "PkiPath", "PKCS7" }));
 | 
						|
 | 
						|
  private static final OID PKCS7_SIGNED_DATA = new OID("1.2.840.113549.1.7.2");
 | 
						|
  private static final OID PKCS7_DATA = new OID("1.2.840.113549.1.7.1");
 | 
						|
 | 
						|
  /** The certificate path. */
 | 
						|
  private List path;
 | 
						|
 | 
						|
  /** The cached PKCS #7 encoded bytes. */
 | 
						|
  private byte[] pkcs_encoded;
 | 
						|
 | 
						|
  /** The cached PkiPath encoded bytes. */
 | 
						|
  private byte[] pki_encoded;
 | 
						|
 | 
						|
  // Constructor.
 | 
						|
  // -------------------------------------------------------------------------
 | 
						|
 | 
						|
  public X509CertPath(List path)
 | 
						|
  {
 | 
						|
    super("X.509");
 | 
						|
    this.path = Collections.unmodifiableList(path);
 | 
						|
  }
 | 
						|
 | 
						|
  public X509CertPath(InputStream in) throws CertificateEncodingException
 | 
						|
  {
 | 
						|
    this(in, (String) ENCODINGS.get(0));
 | 
						|
  }
 | 
						|
 | 
						|
  public X509CertPath(InputStream in, String encoding)
 | 
						|
    throws CertificateEncodingException
 | 
						|
  {
 | 
						|
    super("X.509");
 | 
						|
    try
 | 
						|
      {
 | 
						|
        parse(in, encoding);
 | 
						|
      }
 | 
						|
    catch (IOException ioe)
 | 
						|
      {
 | 
						|
        throw new CertificateEncodingException();
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  // Instance methods.
 | 
						|
  // -------------------------------------------------------------------------
 | 
						|
 | 
						|
  public List getCertificates()
 | 
						|
  {
 | 
						|
    return path; // already unmodifiable
 | 
						|
  }
 | 
						|
 | 
						|
  public byte[] getEncoded() throws CertificateEncodingException
 | 
						|
  {
 | 
						|
    return getEncoded((String) ENCODINGS.get(0));
 | 
						|
  }
 | 
						|
 | 
						|
  public byte[] getEncoded(String encoding) throws CertificateEncodingException
 | 
						|
  {
 | 
						|
    if (encoding.equalsIgnoreCase("PkiPath"))
 | 
						|
      {
 | 
						|
        if (pki_encoded == null)
 | 
						|
          {
 | 
						|
            try
 | 
						|
              {
 | 
						|
                pki_encoded = encodePki();
 | 
						|
              }
 | 
						|
            catch (IOException ioe)
 | 
						|
              {
 | 
						|
                throw new CertificateEncodingException();
 | 
						|
              }
 | 
						|
          }
 | 
						|
        return (byte[]) pki_encoded.clone();
 | 
						|
      }
 | 
						|
    else if (encoding.equalsIgnoreCase("PKCS7"))
 | 
						|
      {
 | 
						|
        if (pkcs_encoded == null)
 | 
						|
          {
 | 
						|
            try
 | 
						|
              {
 | 
						|
                pkcs_encoded = encodePKCS();
 | 
						|
              }
 | 
						|
            catch (IOException ioe)
 | 
						|
              {
 | 
						|
                throw new CertificateEncodingException();
 | 
						|
              }
 | 
						|
          }
 | 
						|
        return (byte[]) pkcs_encoded.clone();
 | 
						|
      }
 | 
						|
    else
 | 
						|
      throw new CertificateEncodingException("unknown encoding: " + encoding);
 | 
						|
  }
 | 
						|
 | 
						|
  public Iterator getEncodings()
 | 
						|
  {
 | 
						|
    return ENCODINGS.iterator(); // already unmodifiable
 | 
						|
  }
 | 
						|
 | 
						|
  // Own methods.
 | 
						|
  // -------------------------------------------------------------------------
 | 
						|
 | 
						|
  private void parse(InputStream in, String encoding)
 | 
						|
    throws CertificateEncodingException, IOException
 | 
						|
  {
 | 
						|
    DERReader der = new DERReader(in);
 | 
						|
    DERValue path = null;
 | 
						|
    if (encoding.equalsIgnoreCase("PkiPath"))
 | 
						|
      {
 | 
						|
        // PKI encoding is just a SEQUENCE of X.509 certificates.
 | 
						|
        path = der.read();
 | 
						|
        if (!path.isConstructed())
 | 
						|
          throw new DEREncodingException("malformed PkiPath");
 | 
						|
      }
 | 
						|
    else if (encoding.equalsIgnoreCase("PKCS7"))
 | 
						|
      {
 | 
						|
        // PKCS #7 encoding means that the certificates are contained in a
 | 
						|
        // SignedData PKCS #7 type.
 | 
						|
        //
 | 
						|
        // ContentInfo ::= SEQUENCE {
 | 
						|
        //   contentType ::= ContentType,
 | 
						|
        //   content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
 | 
						|
        //
 | 
						|
        // ContentType ::= OBJECT IDENTIFIER
 | 
						|
        //
 | 
						|
        // SignedData ::= SEQUENCE {
 | 
						|
        //   version Version,
 | 
						|
        //   digestAlgorithms DigestAlgorithmIdentifiers,
 | 
						|
        //   contentInfo ContentInfo,
 | 
						|
        //   certificates [0] IMPLICIT ExtendedCertificatesAndCertificates
 | 
						|
        //                    OPTIONAL,
 | 
						|
        //   crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
 | 
						|
        //   signerInfos SignerInfos }
 | 
						|
        //
 | 
						|
        // Version ::= INTEGER
 | 
						|
        //
 | 
						|
        DERValue value = der.read();
 | 
						|
        if (!value.isConstructed())
 | 
						|
          throw new DEREncodingException("malformed ContentInfo");
 | 
						|
        value = der.read();
 | 
						|
        if (!(value.getValue() instanceof OID) ||
 | 
						|
            ((OID) value.getValue()).equals(PKCS7_SIGNED_DATA))
 | 
						|
          throw new DEREncodingException("not a SignedData");
 | 
						|
        value = der.read();
 | 
						|
        if (!value.isConstructed() || value.getTag() != 0)
 | 
						|
          throw new DEREncodingException("malformed content");
 | 
						|
        value = der.read();
 | 
						|
        if (value.getTag() != DER.INTEGER)
 | 
						|
          throw new DEREncodingException("malformed Version");
 | 
						|
        value = der.read();
 | 
						|
        if (!value.isConstructed() || value.getTag() != DER.SET)
 | 
						|
          throw new DEREncodingException("malformed DigestAlgorithmIdentifiers");
 | 
						|
        der.skip(value.getLength());
 | 
						|
        value = der.read();
 | 
						|
        if (!value.isConstructed())
 | 
						|
          throw new DEREncodingException("malformed ContentInfo");
 | 
						|
        der.skip(value.getLength());
 | 
						|
        path = der.read();
 | 
						|
        if (!path.isConstructed() || path.getTag() != 0)
 | 
						|
          throw new DEREncodingException("no certificates");
 | 
						|
      }
 | 
						|
    else
 | 
						|
      throw new CertificateEncodingException("unknown encoding: " + encoding);
 | 
						|
 | 
						|
    LinkedList certs = new LinkedList();
 | 
						|
    int len = 0;
 | 
						|
    while (len < path.getLength())
 | 
						|
      {
 | 
						|
        DERValue cert = der.read();
 | 
						|
        try
 | 
						|
          {
 | 
						|
            certs.add(new X509Certificate(new ByteArrayInputStream(cert.getEncoded())));
 | 
						|
          }
 | 
						|
        catch (CertificateException ce)
 | 
						|
          {
 | 
						|
            throw new CertificateEncodingException(ce.getMessage());
 | 
						|
          }
 | 
						|
        len += cert.getEncodedLength();
 | 
						|
        der.skip(cert.getLength());
 | 
						|
      }
 | 
						|
 | 
						|
    this.path = Collections.unmodifiableList(certs);
 | 
						|
  }
 | 
						|
 | 
						|
  private byte[] encodePki()
 | 
						|
    throws CertificateEncodingException, IOException
 | 
						|
  {
 | 
						|
    synchronized (path)
 | 
						|
      {
 | 
						|
        ByteArrayOutputStream out = new ByteArrayOutputStream();
 | 
						|
        for (Iterator i = path.iterator(); i.hasNext(); )
 | 
						|
          {
 | 
						|
            out.write(((Certificate) i.next()).getEncoded());
 | 
						|
          }
 | 
						|
        byte[] b = out.toByteArray();
 | 
						|
        DERValue val = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
 | 
						|
                                    b.length, b, null);
 | 
						|
        return val.getEncoded();
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  private byte[] encodePKCS()
 | 
						|
    throws CertificateEncodingException, IOException
 | 
						|
  {
 | 
						|
    synchronized (path)
 | 
						|
      {
 | 
						|
        ArrayList signedData = new ArrayList(5);
 | 
						|
        signedData.add(new DERValue(DER.INTEGER, BigInteger.ONE));
 | 
						|
        signedData.add(new DERValue(DER.CONSTRUCTED | DER.SET,
 | 
						|
                                    Collections.EMPTY_SET));
 | 
						|
        signedData.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
 | 
						|
          Collections.singletonList(
 | 
						|
            new DERValue(DER.OBJECT_IDENTIFIER, PKCS7_DATA))));
 | 
						|
        ByteArrayOutputStream out = new ByteArrayOutputStream();
 | 
						|
        for (Iterator i = path.iterator(); i.hasNext(); )
 | 
						|
          {
 | 
						|
            out.write(((Certificate) i.next()).getEncoded());
 | 
						|
          }
 | 
						|
        byte[] b = out.toByteArray();
 | 
						|
        signedData.add(new DERValue(DER.CONSTRUCTED | DER.CONTEXT,
 | 
						|
                                    b.length, b, null));
 | 
						|
        DERValue sdValue = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
 | 
						|
                                        signedData);
 | 
						|
 | 
						|
        ArrayList contentInfo = new ArrayList(2);
 | 
						|
        contentInfo.add(new DERValue(DER.OBJECT_IDENTIFIER, PKCS7_SIGNED_DATA));
 | 
						|
        contentInfo.add(new DERValue(DER.CONSTRUCTED | DER.CONTEXT, sdValue));
 | 
						|
        return new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
 | 
						|
                            contentInfo).getEncoded();
 | 
						|
      }
 | 
						|
  }
 | 
						|
}
 |