Engine.java, [...]: New files from classpath.
2003-04-30 Michael Koch <konqueror@gmx.de> * gnu/java/security/Engine.java, gnu/java/security/OID.java, gnu/java/security/der/BitString.java, gnu/java/security/der/DER.java, gnu/java/security/der/DERReader.java, gnu/java/security/der/DERValue.java, gnu/java/security/der/DERWriter.java, gnu/java/security/provider/DSAKeyFactory.java, gnu/java/security/provider/X509CertificateFactory.java, gnu/java/security/x509/X500DistinguishedName.java, gnu/java/security/x509/X509CRL.java, gnu/java/security/x509/X509CRLEntry.java, gnu/java/security/x509/X509Certificate.java, java/security/cert/CRLSelector.java, java/security/cert/CertPathBuilder.java, java/security/cert/CertPathBuilderResult.java, java/security/cert/CertPathBuilderSpi.java, java/security/cert/CertPathParameters.java, java/security/cert/CertPathValidator.java, java/security/cert/CertPathValidatorResult.java, java/security/cert/CertPathValidatorSpi.java, java/security/cert/CertSelector.java, java/security/cert/CertStore.java, java/security/cert/CertStoreParameters.java, java/security/cert/CertStoreSpi.java, java/security/cert/CollectionCertStoreParameters.java, java/security/cert/LDAPCertStoreParameters.java, java/security/cert/PKIXBuilderParameters.java, java/security/cert/PKIXCertPathBuilderResult.java, java/security/cert/PKIXCertPathChecker.java, java/security/cert/PKIXCertPathValidatorResult.java, java/security/cert/PKIXParameters.java, java/security/cert/PolicyNode.java, java/security/cert/PolicyQualifierInfo.java, java/security/cert/TrustAnchor.java, javax/security/auth/x500/X500Principal.java: New files from classpath. * gnu/java/io/ASN1ParsingException.java, gnu/java/io/Base64InputStream.java, gnu/java/security/der/DEREncodingException.java, gnu/java/security/provider/DSAParameters.java, gnu/java/security/provider/DSASignature.java, gnu/java/security/provider/Gnu.java, gnu/java/security/provider/GnuDSAPrivateKey.java, gnu/java/security/provider/GnuDSAPublicKey.java, java/security/AlgorithmParameterGenerator.java, java/security/AlgorithmParameters.java, java/security/KeyFactory.java, java/security/KeyPairGenerator.java, java/security/KeyStore.java, java/security/MessageDigest.java, java/security/SecureClassLoader.java, java/security/SecureRandom.java, java/security/Security.java, java/security/Signature.java, java/security/cert/Certificate.java, java/security/cert/CertificateFactory.java, java/security/cert/CertificateFactorySpi.java, java/security/cert/X509CRL.java, java/security/cert/X509Certificate.java, java/security/spec/DSAPublicKeySpec.java: New versions from classpath. * gnu/java/security/provider/DERReader.java, gnu/java/security/provider/DERWriter.java, java/security/Engine.java: Removed. * Makefile.am (java_source_files, javax_source_files): Added new files. * Makefile.in: Regenerated. From-SVN: r66283
This commit is contained in:
committed by
Michael Koch
parent
505b0fd661
commit
43905ff30b
@@ -0,0 +1,824 @@
|
||||
/* X500DistinguishedName.java -- X.500 name.
|
||||
Copyright (C) 2003 Free Software Foundation, 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.io.StreamTokenizer;
|
||||
import java.io.StringReader;
|
||||
|
||||
import java.security.Principal;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import gnu.java.io.ASN1ParsingException;
|
||||
import gnu.java.security.OID;
|
||||
import gnu.java.security.der.DER;
|
||||
import gnu.java.security.der.DERReader;
|
||||
import gnu.java.security.der.DERValue;
|
||||
import gnu.java.security.der.DERWriter;
|
||||
|
||||
/**
|
||||
* A X.500 distinguished name. Distinguished names are sequences of
|
||||
* ATTRIB=VALUE pairs, where ATTRIB is one of the following:
|
||||
*
|
||||
* <table cellpadding="0" cellspacing="0" border="0">
|
||||
* <tr>
|
||||
* <th bgcolor="#CCCCFF" align="left">Name</th>
|
||||
* <th bgcolor="#CCCCFF" align="left">X.500 AttributeType</th>
|
||||
* <th bgcolor="#CCCCFF" align="left">ObjectIdentifier</th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td align="left">CN</td>
|
||||
* <td align="left">commonName</td>
|
||||
* <td align="left">2.5.4.3</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td align="left">C</td>
|
||||
* <td align="left">countryName</td>
|
||||
* <td align="left">2.5.4.6</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td align="left">L</td>
|
||||
* <td align="left">localityName</td>
|
||||
* <td align="left">2.5.4.7</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td align="left">ST</td>
|
||||
* <td align="left">stateOrProvinceName</td>
|
||||
* <td align="left">2.5.4.8</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td align="left">STREET</td>
|
||||
* <td align="left">streetAddress</td>
|
||||
* <td align="left">2.5.4.9</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td align="left">O</td>
|
||||
* <td align="left">organizationName</td>
|
||||
* <td align="left">2.5.4.10</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td align="left">OU</td>
|
||||
* <td align="left">organizationUnitName</td>
|
||||
* <td align="left">2.5.4.11</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td align="left">DC</td>
|
||||
* <td align="left">domainComponent</td>
|
||||
* <td align="left">0.9.2342.19200300.100.1.25</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td align="left">UID</td>
|
||||
* <td align="left">userid</td>
|
||||
* <td align="left"0.9.2342.19200300.100.1.1></td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td align="left">DNQ or DNQUALIFIER(*)</td>
|
||||
* <td align="left">domainNameQualifier</td>
|
||||
* <td align="left">2.5.4.46</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td align="left">SURNAME(*)</td>
|
||||
* <td align="left">name</td>
|
||||
* <td align="left">2.5.4.41</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td align="left">GIVENNAME(*)</td>
|
||||
* <td align="left">givenName</td>
|
||||
* <td align="left">2.5.4.42</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td align="left">INITIALS(*)</td>
|
||||
* <td align="left">initials</td>
|
||||
* <td align="left">2.5.4.43</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td align="left">EMAILADDRESS(*)</td>
|
||||
* <td align="left">emailAddress</td>
|
||||
* <td align="left">2.5.4.44</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*
|
||||
* <p><i>(*) = attributes not specified in RFC1779 or RFC2253, but
|
||||
* recognized anyway.</i>
|
||||
*
|
||||
* <p>Distinguished names of this form are used in the lightweight
|
||||
* directory access protocol (LDAP) and in the issuer and subject fields
|
||||
* of X.509 certificates.
|
||||
*
|
||||
* @author Casey Marshall (rsdio@metastatic.org)
|
||||
* @see javax.security.auth.x500.X500Principal
|
||||
* @status DER decoding/encoding works, RFC1779 and RFC2253 need to be
|
||||
* made more robust.
|
||||
*/
|
||||
public class X500DistinguishedName
|
||||
{
|
||||
|
||||
// Constants and fields.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
public static final OID CN = new OID("2.5.4.3");
|
||||
public static final OID C = new OID("2.5.4.6");
|
||||
public static final OID L = new OID("2.5.4.7");
|
||||
public static final OID ST = new OID("2.5.4.8");
|
||||
public static final OID STREET = new OID("2.5.4.9");
|
||||
public static final OID O = new OID("2.5.4.10");
|
||||
public static final OID OU = new OID("2.5.4.11");
|
||||
public static final OID T = new OID("2.5.4.12");
|
||||
public static final OID DNQ = new OID("2.5.4.46");
|
||||
public static final OID NAME = new OID("2.5.4.41");
|
||||
public static final OID GIVENNAME = new OID("2.5.4.42");
|
||||
public static final OID INITIALS = new OID("2.5.4.43");
|
||||
public static final OID GENERATION = new OID("2.5.4.44");
|
||||
public static final OID EMAIL = new OID("1.2.840.113549.1.9.1");
|
||||
public static final OID DC = new OID("0.9.2342.19200300.100.1.25");
|
||||
public static final OID UID = new OID("0.9.2342.19200300.100.1.1");
|
||||
|
||||
private String commonName;
|
||||
private String country;
|
||||
private String locality;
|
||||
private String orgUnit;
|
||||
private String organization;
|
||||
private String street;
|
||||
private String state;
|
||||
private String title;
|
||||
private String dnQualifier;
|
||||
private String surname;
|
||||
private String givenName;
|
||||
private String initials;
|
||||
private String generation;
|
||||
private String email;
|
||||
private String domainComponent;
|
||||
private String userid;
|
||||
|
||||
private String nameRFC1779;
|
||||
private String nameRFC2253;
|
||||
private String nameCanonical;
|
||||
|
||||
private transient byte[] encoded;
|
||||
|
||||
// Constructors.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Create a new X500DistinguishedName from the RFC1779 or RFC2253
|
||||
* encoded form.
|
||||
*
|
||||
* @param name The encoded name.
|
||||
* @throws IllegalArgumentException If the name cannot be parsed.
|
||||
*/
|
||||
public X500DistinguishedName(String name)
|
||||
{
|
||||
if (name == null)
|
||||
throw new NullPointerException();
|
||||
try
|
||||
{
|
||||
parseDN(name, true);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
parseDN(name, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new X500DistinguishedName from the DER encoded bytes.
|
||||
*
|
||||
* @param encoded The encoded form.
|
||||
* @throws IOException If the bytes are not a valid DER construct.
|
||||
*/
|
||||
public X500DistinguishedName(byte[] encoded) throws IOException
|
||||
{
|
||||
this(new ByteArrayInputStream(encoded));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new X500DistinguishedName from the DER encoded bytes.
|
||||
*
|
||||
* @param encoded The encoded form.
|
||||
* @throws IOException If the bytes are not a valid DER construct.
|
||||
*/
|
||||
public X500DistinguishedName(InputStream encoded) throws IOException
|
||||
{
|
||||
parseDER(encoded);
|
||||
}
|
||||
|
||||
// Instance methods.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
return
|
||||
(commonName != null &&
|
||||
commonName.equals(((X500DistinguishedName) o).commonName)) &&
|
||||
(country != null &&
|
||||
country.equals(((X500DistinguishedName) o).country)) &&
|
||||
(locality != null &&
|
||||
locality.equals(((X500DistinguishedName) o).locality)) &&
|
||||
(orgUnit != null &&
|
||||
orgUnit.equals(((X500DistinguishedName) o).orgUnit)) &&
|
||||
(organization != null &&
|
||||
organization.equals(((X500DistinguishedName) o).organization)) &&
|
||||
(street != null &&
|
||||
street.equals(((X500DistinguishedName) o).street)) &&
|
||||
(state != null &&
|
||||
state.equals(((X500DistinguishedName) o).state)) &&
|
||||
(domainComponent != null &&
|
||||
domainComponent.equals(((X500DistinguishedName) o).domainComponent)) &&
|
||||
(title != null &&
|
||||
title.equals(((X500DistinguishedName) o).title)) &&
|
||||
(dnQualifier != null &&
|
||||
dnQualifier.equals(((X500DistinguishedName) o).dnQualifier)) &&
|
||||
(surname != null &&
|
||||
surname.equals(((X500DistinguishedName) o).surname)) &&
|
||||
(givenName != null &&
|
||||
givenName.equals(((X500DistinguishedName) o).givenName)) &&
|
||||
(initials != null &&
|
||||
initials.equals(((X500DistinguishedName) o).initials)) &&
|
||||
(generation != null &&
|
||||
generation.equals(((X500DistinguishedName) o).generation)) &&
|
||||
(email != null &&
|
||||
email.equals(((X500DistinguishedName) o).email)) &&
|
||||
(userid != null &&
|
||||
userid.equals(((X500DistinguishedName) o).userid));
|
||||
}
|
||||
|
||||
public byte[] getEncoded()
|
||||
{
|
||||
if (encoded == null)
|
||||
encoded = encodeDER();
|
||||
return (byte[]) encoded.clone();
|
||||
}
|
||||
|
||||
private static String quote(String str)
|
||||
{
|
||||
if (str.indexOf(" ") > 0 || str.indexOf("\f") > 0 ||
|
||||
str.indexOf("\n") > 0 || str.indexOf("\r") > 0 ||
|
||||
str.indexOf("\t") > 0)
|
||||
str = '"' + str + '"';
|
||||
// XXX needs regex
|
||||
//return str.replaceAll("([,+\"\\<>;])", "\\\1");
|
||||
return str;
|
||||
}
|
||||
|
||||
public String toRFC1779()
|
||||
{
|
||||
if (nameRFC1779 != null)
|
||||
return nameRFC1779;
|
||||
StringBuffer buf = new StringBuffer();
|
||||
if (commonName != null)
|
||||
buf.append("CN=").append(quote(commonName)).append(", ");
|
||||
if (country != null)
|
||||
buf.append("C=").append(quote(country)).append(", ");
|
||||
if (locality != null)
|
||||
buf.append("L=").append(quote(locality)).append(", ");
|
||||
if (orgUnit != null)
|
||||
buf.append("OU=").append(quote(orgUnit)).append(", ");
|
||||
if (organization != null)
|
||||
buf.append("O=").append(quote(organization)).append(", ");
|
||||
if (street != null)
|
||||
buf.append("STREET=").append(quote(street)).append(", ");
|
||||
if (state != null)
|
||||
buf.append("ST=").append(quote(state)).append(", ");
|
||||
if (title != null)
|
||||
buf.append(T).append("=").append(quote(title)).append(", ");
|
||||
if (dnQualifier != null)
|
||||
buf.append(DNQ).append("=").append(quote(dnQualifier)).append(", ");
|
||||
if (surname != null)
|
||||
buf.append(NAME).append("=").append(quote(surname)).append(", ");
|
||||
if (givenName != null)
|
||||
buf.append(GIVENNAME).append("=").append(quote(givenName)).append(", ");
|
||||
if (initials != null)
|
||||
buf.append(INITIALS).append("=").append(quote(initials)).append(", ");
|
||||
if (generation != null)
|
||||
buf.append(GENERATION).append("=").append(quote(generation)).append(", ");
|
||||
if (email != null)
|
||||
buf.append(EMAIL).append("=").append(quote(email)).append(", ");
|
||||
if (domainComponent != null)
|
||||
buf.append(DC).append("=").append(quote(domainComponent)).append(", ");
|
||||
if (userid != null)
|
||||
buf.append(UID).append("=").append(quote(userid)).append(", ");
|
||||
// XXX escapes
|
||||
return (nameRFC1779 = buf.substring(0, buf.length()-2));
|
||||
}
|
||||
|
||||
public String toRFC2253()
|
||||
{
|
||||
if (nameRFC2253 != null)
|
||||
return nameRFC2253;
|
||||
StringBuffer buf = new StringBuffer();
|
||||
if (commonName != null)
|
||||
buf.append("CN=").append(quote(commonName)).append(",");
|
||||
if (country != null)
|
||||
buf.append("C=").append(quote(country)).append(",");
|
||||
if (locality != null)
|
||||
buf.append("L=").append(quote(locality)).append(",");
|
||||
if (orgUnit != null)
|
||||
buf.append("OU=").append(quote(orgUnit)).append(",");
|
||||
if (organization != null)
|
||||
buf.append("O=").append(quote(organization)).append(",");
|
||||
if (street != null)
|
||||
buf.append("STREET=").append(quote(street)).append(",");
|
||||
if (state != null)
|
||||
buf.append("ST=").append(quote(state)).append(",");
|
||||
if (title != null)
|
||||
buf.append(T).append("=").append(quote(title)).append(",");
|
||||
if (dnQualifier != null)
|
||||
buf.append(DNQ).append("=").append(quote(dnQualifier)).append(",");
|
||||
if (surname != null)
|
||||
buf.append(NAME).append("=").append(quote(surname)).append(",");
|
||||
if (givenName != null)
|
||||
buf.append(GIVENNAME).append("=").append(quote(givenName)).append(",");
|
||||
if (initials != null)
|
||||
buf.append(INITIALS).append("=").append(quote(initials)).append(",");
|
||||
if (generation != null)
|
||||
buf.append(GENERATION).append("=").append(quote(generation)).append(",");
|
||||
if (email != null)
|
||||
buf.append(EMAIL).append("=").append(quote(email)).append(",");
|
||||
if (domainComponent != null)
|
||||
buf.append(DC).append("=").append(quote(domainComponent)).append(",");
|
||||
if (userid != null)
|
||||
buf.append(UID).append("=").append(quote(userid)).append(",");
|
||||
// XXX escapes.
|
||||
return (nameRFC2253 = buf.substring(0, buf.length()-1));
|
||||
}
|
||||
|
||||
public String toCanonical()
|
||||
{
|
||||
if (nameCanonical != null)
|
||||
return nameCanonical;
|
||||
nameCanonical = toRFC2253();
|
||||
return nameCanonical; // XXX canonicalize
|
||||
}
|
||||
|
||||
public String getCommonName()
|
||||
{
|
||||
return commonName;
|
||||
}
|
||||
|
||||
public String getCountry()
|
||||
{
|
||||
return country;
|
||||
}
|
||||
|
||||
public String getLocality()
|
||||
{
|
||||
return locality;
|
||||
}
|
||||
|
||||
public String getOrganizationalUnit()
|
||||
{
|
||||
return orgUnit;
|
||||
}
|
||||
|
||||
public String getOrganization()
|
||||
{
|
||||
return organization;
|
||||
}
|
||||
|
||||
public String getStreet()
|
||||
{
|
||||
return street;
|
||||
}
|
||||
|
||||
public String getState()
|
||||
{
|
||||
return state;
|
||||
}
|
||||
|
||||
public String getTitle()
|
||||
{
|
||||
return title;
|
||||
}
|
||||
|
||||
public String getDNQualifier()
|
||||
{
|
||||
return dnQualifier;
|
||||
}
|
||||
|
||||
public String getSurname()
|
||||
{
|
||||
return surname;
|
||||
}
|
||||
|
||||
public String getGivenName()
|
||||
{
|
||||
return givenName;
|
||||
}
|
||||
|
||||
public String getInitials()
|
||||
{
|
||||
return initials;
|
||||
}
|
||||
|
||||
public String getGeneration()
|
||||
{
|
||||
return generation;
|
||||
}
|
||||
|
||||
public String getEmail()
|
||||
{
|
||||
return email;
|
||||
}
|
||||
|
||||
public String getDomain()
|
||||
{
|
||||
return domainComponent;
|
||||
}
|
||||
|
||||
public String getUserID()
|
||||
{
|
||||
return userid;
|
||||
}
|
||||
|
||||
// Own methods.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
private static String unquote(String str)
|
||||
{
|
||||
if (str.startsWith("\"") && str.endsWith("\""))
|
||||
str = str.substring(1, str.length()-1);
|
||||
// XXX needs regex
|
||||
//return str.replaceAll("\\([,+\"\\<>;])", "\1");
|
||||
return str;
|
||||
}
|
||||
|
||||
private void parseDN(String name, boolean rfc2253)
|
||||
{
|
||||
if (name.length() == 0)
|
||||
throw new IllegalArgumentException("zero-length distinguished name");
|
||||
StreamTokenizer parse = new StreamTokenizer(new StringReader(name));
|
||||
parse.resetSyntax();
|
||||
parse.wordChars('\000', '~');
|
||||
parse.ordinaryChar('#');
|
||||
parse.ordinaryChar(',');
|
||||
parse.ordinaryChar('=');
|
||||
parse.ordinaryChar('<');
|
||||
parse.ordinaryChar('>');
|
||||
parse.ordinaryChar(';');
|
||||
parse.ordinaryChar('\\');
|
||||
parse.quoteChar('"');
|
||||
String attrib = null;
|
||||
String value = null;
|
||||
int token, lastToken = ',';
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
token = parse.nextToken();
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
switch (token)
|
||||
{
|
||||
case StreamTokenizer.TT_WORD:
|
||||
if (lastToken == ',' || lastToken == '+' ||
|
||||
(!rfc2253 && lastToken == ';'))
|
||||
attrib = parse.sval.trim();
|
||||
else if (lastToken == '=')
|
||||
value = unquote(parse.sval.trim());
|
||||
else
|
||||
throw new IllegalArgumentException();
|
||||
break;
|
||||
case '"':
|
||||
if (lastToken == '=')
|
||||
value = parse.sval;
|
||||
else
|
||||
throw new IllegalArgumentException();
|
||||
break;
|
||||
case ';':
|
||||
if (rfc2253)
|
||||
throw new IllegalArgumentException();
|
||||
case ',':
|
||||
case '+':
|
||||
if (attrib == null || value == null)
|
||||
throw new IllegalArgumentException("extraneous separator");
|
||||
try
|
||||
{
|
||||
setAttribute(new OID(attrib), value);
|
||||
}
|
||||
catch (Exception x)
|
||||
{
|
||||
setAttribute(attrib, value);
|
||||
}
|
||||
attrib = null;
|
||||
value = null;
|
||||
break;
|
||||
case '=':
|
||||
break;
|
||||
case StreamTokenizer.TT_EOF:
|
||||
return;
|
||||
default:
|
||||
throw new IllegalArgumentException("unknown token " + (char)token
|
||||
+ " (" + token + ")");
|
||||
}
|
||||
lastToken = token;
|
||||
}
|
||||
}
|
||||
|
||||
private void parseDER(InputStream in) throws IOException
|
||||
{
|
||||
DERReader der = new DERReader(in);
|
||||
DERValue name = der.read();
|
||||
if (!name.isConstructed())
|
||||
throw new ASN1ParsingException("badly formed Name");
|
||||
int len = 0;
|
||||
while (len < name.getLength())
|
||||
{
|
||||
DERValue rdn = der.read();
|
||||
if (rdn.getValue() != DER.CONSTRUCTED_VALUE)
|
||||
throw new ASN1ParsingException("badly formed RDNSequence");
|
||||
int len2 = 0;
|
||||
while (len2 < rdn.getLength())
|
||||
{
|
||||
DERValue atav = der.read();
|
||||
if (atav.getValue() != DER.CONSTRUCTED_VALUE)
|
||||
throw new ASN1ParsingException(
|
||||
"badly formed AttributeTypeAndValue");
|
||||
OID atype = (OID) der.read().getValue();
|
||||
String aval = (String) der.read().getValue();
|
||||
setAttribute(atype, aval);
|
||||
len2 += 1 + atav.getLength()
|
||||
+ DERWriter.definiteEncodingSize(atav.getLength());
|
||||
}
|
||||
len += len2 + 1 + DERWriter.definiteEncodingSize(name.getLength());
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] encodeDER()
|
||||
{
|
||||
try
|
||||
{
|
||||
LinkedList name = new LinkedList();
|
||||
if (commonName != null)
|
||||
{
|
||||
HashSet rdn = new HashSet();
|
||||
LinkedList atav = new LinkedList();
|
||||
atav.add(new DERValue(DER.OBJECT_IDENTIFIER, CN));
|
||||
atav.add(new DERValue(DER.PRINTABLE_STRING, commonName));
|
||||
rdn.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, atav));
|
||||
name.add(new DERValue(DER.CONSTRUCTED | DER.SET, rdn));
|
||||
}
|
||||
if (country != null)
|
||||
{
|
||||
HashSet rdn = new HashSet();
|
||||
LinkedList atav = new LinkedList();
|
||||
atav.add(new DERValue(DER.OBJECT_IDENTIFIER, C));
|
||||
atav.add(new DERValue(DER.PRINTABLE_STRING, country));
|
||||
rdn.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, atav));
|
||||
name.add(new DERValue(DER.CONSTRUCTED | DER.SET, rdn));
|
||||
}
|
||||
if (locality != null)
|
||||
{
|
||||
HashSet rdn = new HashSet();
|
||||
LinkedList atav = new LinkedList();
|
||||
atav.add(new DERValue(DER.OBJECT_IDENTIFIER, L));
|
||||
atav.add(new DERValue(DER.PRINTABLE_STRING, locality));
|
||||
rdn.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, atav));
|
||||
name.add(new DERValue(DER.CONSTRUCTED | DER.SET, rdn));
|
||||
}
|
||||
if (orgUnit != null)
|
||||
{
|
||||
HashSet rdn = new HashSet();
|
||||
LinkedList atav = new LinkedList();
|
||||
atav.add(new DERValue(DER.OBJECT_IDENTIFIER, OU));
|
||||
atav.add(new DERValue(DER.PRINTABLE_STRING, orgUnit));
|
||||
rdn.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, atav));
|
||||
name.add(new DERValue(DER.CONSTRUCTED | DER.SET, rdn));
|
||||
}
|
||||
if (organization != null)
|
||||
{
|
||||
HashSet rdn = new HashSet();
|
||||
LinkedList atav = new LinkedList();
|
||||
atav.add(new DERValue(DER.OBJECT_IDENTIFIER, O));
|
||||
atav.add(new DERValue(DER.PRINTABLE_STRING, organization));
|
||||
rdn.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, atav));
|
||||
name.add(new DERValue(DER.CONSTRUCTED | DER.SET, rdn));
|
||||
}
|
||||
if (street != null)
|
||||
{
|
||||
HashSet rdn = new HashSet();
|
||||
LinkedList atav = new LinkedList();
|
||||
atav.add(new DERValue(DER.OBJECT_IDENTIFIER, STREET));
|
||||
atav.add(new DERValue(DER.PRINTABLE_STRING, street));
|
||||
rdn.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, atav));
|
||||
name.add(new DERValue(DER.CONSTRUCTED | DER.SET, rdn));
|
||||
}
|
||||
if (state != null)
|
||||
{
|
||||
HashSet rdn = new HashSet();
|
||||
LinkedList atav = new LinkedList();
|
||||
atav.add(new DERValue(DER.OBJECT_IDENTIFIER, ST));
|
||||
atav.add(new DERValue(DER.PRINTABLE_STRING, state));
|
||||
rdn.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, atav));
|
||||
name.add(new DERValue(DER.CONSTRUCTED | DER.SET, rdn));
|
||||
}
|
||||
if (title != null)
|
||||
{
|
||||
HashSet rdn = new HashSet();
|
||||
LinkedList atav = new LinkedList();
|
||||
atav.add(new DERValue(DER.OBJECT_IDENTIFIER, T));
|
||||
atav.add(new DERValue(DER.PRINTABLE_STRING, title));
|
||||
rdn.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, atav));
|
||||
name.add(new DERValue(DER.CONSTRUCTED | DER.SET, rdn));
|
||||
}
|
||||
if (dnQualifier != null)
|
||||
{
|
||||
HashSet rdn = new HashSet();
|
||||
LinkedList atav = new LinkedList();
|
||||
atav.add(new DERValue(DER.OBJECT_IDENTIFIER, DNQ));
|
||||
atav.add(new DERValue(DER.PRINTABLE_STRING, dnQualifier));
|
||||
rdn.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, atav));
|
||||
name.add(new DERValue(DER.CONSTRUCTED | DER.SET, rdn));
|
||||
}
|
||||
if (surname != null)
|
||||
{
|
||||
HashSet rdn = new HashSet();
|
||||
LinkedList atav = new LinkedList();
|
||||
atav.add(new DERValue(DER.OBJECT_IDENTIFIER, NAME));
|
||||
atav.add(new DERValue(DER.PRINTABLE_STRING, surname));
|
||||
rdn.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, atav));
|
||||
name.add(new DERValue(DER.CONSTRUCTED | DER.SET, rdn));
|
||||
}
|
||||
if (givenName != null)
|
||||
{
|
||||
HashSet rdn = new HashSet();
|
||||
LinkedList atav = new LinkedList();
|
||||
atav.add(new DERValue(DER.OBJECT_IDENTIFIER, GIVENNAME));
|
||||
atav.add(new DERValue(DER.PRINTABLE_STRING, givenName));
|
||||
rdn.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, atav));
|
||||
name.add(new DERValue(DER.CONSTRUCTED | DER.SET, rdn));
|
||||
}
|
||||
if (initials != null)
|
||||
{
|
||||
HashSet rdn = new HashSet();
|
||||
LinkedList atav = new LinkedList();
|
||||
atav.add(new DERValue(DER.OBJECT_IDENTIFIER, INITIALS));
|
||||
atav.add(new DERValue(DER.PRINTABLE_STRING, initials));
|
||||
rdn.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, atav));
|
||||
name.add(new DERValue(DER.CONSTRUCTED | DER.SET, rdn));
|
||||
}
|
||||
if (generation != null)
|
||||
{
|
||||
HashSet rdn = new HashSet();
|
||||
LinkedList atav = new LinkedList();
|
||||
atav.add(new DERValue(DER.OBJECT_IDENTIFIER, GENERATION));
|
||||
atav.add(new DERValue(DER.PRINTABLE_STRING, generation));
|
||||
rdn.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, atav));
|
||||
name.add(new DERValue(DER.CONSTRUCTED | DER.SET, rdn));
|
||||
}
|
||||
if (email != null)
|
||||
{
|
||||
HashSet rdn = new HashSet();
|
||||
LinkedList atav = new LinkedList();
|
||||
atav.add(new DERValue(DER.OBJECT_IDENTIFIER, EMAIL));
|
||||
atav.add(new DERValue(DER.PRINTABLE_STRING, email));
|
||||
rdn.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, atav));
|
||||
name.add(new DERValue(DER.CONSTRUCTED | DER.SET, rdn));
|
||||
}
|
||||
if (domainComponent != null)
|
||||
{
|
||||
HashSet rdn = new HashSet();
|
||||
LinkedList atav = new LinkedList();
|
||||
atav.add(new DERValue(DER.OBJECT_IDENTIFIER, DC));
|
||||
atav.add(new DERValue(DER.PRINTABLE_STRING, domainComponent));
|
||||
rdn.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, atav));
|
||||
name.add(new DERValue(DER.CONSTRUCTED | DER.SET, rdn));
|
||||
}
|
||||
if (userid != null)
|
||||
{
|
||||
HashSet rdn = new HashSet();
|
||||
LinkedList atav = new LinkedList();
|
||||
atav.add(new DERValue(DER.OBJECT_IDENTIFIER, UID));
|
||||
atav.add(new DERValue(DER.PRINTABLE_STRING, userid));
|
||||
rdn.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, atav));
|
||||
name.add(new DERValue(DER.CONSTRUCTED | DER.SET, rdn));
|
||||
}
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
DERWriter.write(out, new DERValue(DER.CONSTRUCTED|DER.SEQUENCE, name));
|
||||
return out.toByteArray();
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
throw new Error(ioe);
|
||||
}
|
||||
}
|
||||
|
||||
private void setAttribute(String atype, String aval)
|
||||
{
|
||||
if (atype.equals("CN"))
|
||||
commonName = aval;
|
||||
else if (atype.equals("C"))
|
||||
country = aval;
|
||||
else if (atype.equals("L"))
|
||||
locality = aval;
|
||||
else if (atype.equals("ST"))
|
||||
state = aval;
|
||||
else if (atype.equals("STREET"))
|
||||
street = aval;
|
||||
else if (atype.equals("O"))
|
||||
organization = aval;
|
||||
else if (atype.equals("OU"))
|
||||
orgUnit = aval;
|
||||
else if (atype.equals("T"))
|
||||
title = aval;
|
||||
else if (atype.equals("DNQ") || atype.equals("DNQUALIFIER"))
|
||||
dnQualifier = aval;
|
||||
else if (atype.equals("SURNAME"))
|
||||
surname = aval;
|
||||
else if (atype.equals("GIVENNAME"))
|
||||
givenName = aval;
|
||||
else if (atype.equals("INITIALS"))
|
||||
initials = aval;
|
||||
else if (atype.equals("GENERATION"))
|
||||
generation = aval;
|
||||
else if (atype.equals("EMAILADDRESS"))
|
||||
email = aval;
|
||||
else if (atype.equals("DC"))
|
||||
domainComponent = aval;
|
||||
else if (atype.equals("UID"))
|
||||
userid = aval;
|
||||
else
|
||||
throw new IllegalArgumentException("unknown attribute " + atype);
|
||||
}
|
||||
|
||||
private void setAttribute(OID atype, String aval)
|
||||
{
|
||||
if (atype.equals(CN))
|
||||
commonName = aval;
|
||||
else if (atype.equals(C))
|
||||
country = aval;
|
||||
else if (atype.equals(L))
|
||||
locality = aval;
|
||||
else if (atype.equals(ST))
|
||||
state = aval;
|
||||
else if (atype.equals(STREET))
|
||||
street = aval;
|
||||
else if (atype.equals(O))
|
||||
organization = aval;
|
||||
else if (atype.equals(OU))
|
||||
orgUnit = aval;
|
||||
else if (atype.equals(T))
|
||||
title = aval;
|
||||
else if (atype.equals(DNQ))
|
||||
dnQualifier = aval;
|
||||
else if (atype.equals(NAME))
|
||||
surname = aval;
|
||||
else if (atype.equals(GIVENNAME))
|
||||
givenName = aval;
|
||||
else if (atype.equals(INITIALS))
|
||||
initials = aval;
|
||||
else if (atype.equals(GENERATION))
|
||||
generation = aval;
|
||||
else if (atype.equals(EMAIL))
|
||||
email = aval;
|
||||
else if (atype.equals(DC))
|
||||
domainComponent = aval;
|
||||
else if (atype.equals(UID))
|
||||
userid = aval;
|
||||
else
|
||||
throw new IllegalArgumentException("unknown attribute " + atype);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,404 @@
|
||||
/* X509CRL.java -- X.509 certificate revocation list.
|
||||
Copyright (C) 2003 Free Software Foundation, 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.InputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.Set;
|
||||
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.security.PublicKey;
|
||||
import java.security.Principal;
|
||||
import java.security.Signature;
|
||||
import java.security.SignatureException;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CRLException;
|
||||
import java.security.cert.X509CRLEntry;
|
||||
|
||||
import javax.security.auth.x500.X500Principal;
|
||||
|
||||
import gnu.java.io.ASN1ParsingException;
|
||||
import gnu.java.security.OID;
|
||||
import gnu.java.security.der.BitString;
|
||||
import gnu.java.security.der.DER;
|
||||
import gnu.java.security.der.DERReader;
|
||||
import gnu.java.security.der.DERValue;
|
||||
import gnu.java.security.der.DERWriter;
|
||||
|
||||
/**
|
||||
* X.509 certificate revocation lists.
|
||||
*
|
||||
* @author Casey Marshall (rsdio@metastatic.org)
|
||||
*/
|
||||
public class X509CRL extends java.security.cert.X509CRL
|
||||
{
|
||||
|
||||
// Constants and fields.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
private static final OID ID_DSA = new OID("1.2.840.10040.4.1");
|
||||
private static final OID ID_DSA_WITH_SHA1 = new OID("1.2.840.10040.4.3");
|
||||
private static final OID ID_RSA = new OID("1.2.840.113549.1.1.1");
|
||||
private static final OID ID_RSA_WITH_MD2 = new OID("1.2.840.113549.1.1.2");
|
||||
private static final OID ID_RSA_WITH_MD5 = new OID("1.2.840.113549.1.1.4");
|
||||
private static final OID ID_RSA_WITH_SHA1 = new OID("1.2.840.113549.1.1.5");
|
||||
|
||||
private byte[] encoded;
|
||||
|
||||
private byte[] tbsCRLBytes;
|
||||
private int version;
|
||||
private OID algId;
|
||||
private byte[] algParams;
|
||||
private Date thisUpdate;
|
||||
private Date nextUpdate;
|
||||
private X500Principal issuerDN;
|
||||
private HashMap revokedCerts;
|
||||
private HashMap extensions;
|
||||
private HashSet critOids;
|
||||
private HashSet nonCritOids;
|
||||
|
||||
private OID sigAlg;
|
||||
private byte[] sigAlgParams;
|
||||
private byte[] rawSig;
|
||||
private byte[] signature;
|
||||
|
||||
// Constructors.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Create a new X.509 CRL.
|
||||
*
|
||||
* @param encoded The DER encoded CRL.
|
||||
* @throws CRLException If the input bytes are incorrect.
|
||||
* @throws IOException If the input bytes cannot be read.
|
||||
*/
|
||||
public X509CRL(InputStream encoded) throws CRLException, IOException
|
||||
{
|
||||
super();
|
||||
revokedCerts = new HashMap();
|
||||
extensions = new HashMap();
|
||||
critOids = new HashSet();
|
||||
nonCritOids = new HashSet();
|
||||
try
|
||||
{
|
||||
parse(encoded);
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
ioe.printStackTrace();
|
||||
throw ioe;
|
||||
}
|
||||
catch (Exception x)
|
||||
{
|
||||
x.printStackTrace();
|
||||
throw new CRLException(x.toString());
|
||||
}
|
||||
}
|
||||
|
||||
// X509CRL methods.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
return ((X509CRL) o).revokedCerts.equals(revokedCerts);
|
||||
}
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
return revokedCerts.hashCode();
|
||||
}
|
||||
|
||||
public byte[] getEncoded() throws CRLException
|
||||
{
|
||||
return (byte[]) encoded.clone();
|
||||
}
|
||||
|
||||
public void verify(PublicKey key)
|
||||
throws CRLException, NoSuchAlgorithmException, InvalidKeyException,
|
||||
NoSuchProviderException, SignatureException
|
||||
{
|
||||
Signature sig = Signature.getInstance(sigAlg.toString());
|
||||
doVerify(sig, key);
|
||||
}
|
||||
|
||||
public void verify(PublicKey key, String provider)
|
||||
throws CRLException, NoSuchAlgorithmException, InvalidKeyException,
|
||||
NoSuchProviderException, SignatureException
|
||||
{
|
||||
Signature sig = Signature.getInstance(sigAlg.toString(), provider);
|
||||
doVerify(sig, key);
|
||||
}
|
||||
|
||||
public int getVersion()
|
||||
{
|
||||
return version;
|
||||
}
|
||||
|
||||
public Principal getIssuerDN()
|
||||
{
|
||||
return issuerDN;
|
||||
}
|
||||
|
||||
public X500Principal getIssuerX500Principal()
|
||||
{
|
||||
return issuerDN;
|
||||
}
|
||||
|
||||
public Date getThisUpdate()
|
||||
{
|
||||
return (Date) thisUpdate.clone();
|
||||
}
|
||||
|
||||
public Date getNextUpdate()
|
||||
{
|
||||
if (nextUpdate != null)
|
||||
return (Date) nextUpdate.clone();
|
||||
return null;
|
||||
}
|
||||
|
||||
public X509CRLEntry getRevokedCertificate(BigInteger serialNo)
|
||||
{
|
||||
return (X509CRLEntry) revokedCerts.get(serialNo);
|
||||
}
|
||||
|
||||
public Set getRevokedCertificates()
|
||||
{
|
||||
return Collections.unmodifiableSet(new HashSet(revokedCerts.values()));
|
||||
}
|
||||
|
||||
public byte[] getTBSCertList() throws CRLException
|
||||
{
|
||||
return (byte[]) tbsCRLBytes.clone();
|
||||
}
|
||||
|
||||
public byte[] getSignature()
|
||||
{
|
||||
return (byte[]) rawSig.clone();
|
||||
}
|
||||
|
||||
public String getSigAlgName()
|
||||
{
|
||||
if (sigAlg.equals(ID_DSA_WITH_SHA1))
|
||||
return "SHA1withDSA";
|
||||
if (sigAlg.equals(ID_RSA_WITH_MD2))
|
||||
return "MD2withRSA";
|
||||
if (sigAlg.equals(ID_RSA_WITH_MD5))
|
||||
return "MD5withRSA";
|
||||
if (sigAlg.equals(ID_RSA_WITH_SHA1))
|
||||
return "SHA1withRSA";
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
public String getSigAlgOID()
|
||||
{
|
||||
return sigAlg.toString();
|
||||
}
|
||||
|
||||
public byte[] getSigAlgParams()
|
||||
{
|
||||
if (sigAlgParams != null)
|
||||
return (byte[]) sigAlgParams.clone();
|
||||
return null;
|
||||
}
|
||||
|
||||
// X509Extension methods.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
public boolean hasUnsupportedCriticalExtension()
|
||||
{
|
||||
return false; // XXX
|
||||
}
|
||||
|
||||
public Set getCriticalExtensionOIDs()
|
||||
{
|
||||
return Collections.unmodifiableSet(critOids);
|
||||
}
|
||||
|
||||
public Set getNonCriticalExtensionOIDs()
|
||||
{
|
||||
return Collections.unmodifiableSet(nonCritOids);
|
||||
}
|
||||
|
||||
public byte[] getExtensionValue(String oid)
|
||||
{
|
||||
byte[] ext = (byte[]) extensions.get(oid);
|
||||
if (ext != null)
|
||||
return (byte[]) ext.clone();
|
||||
return null;
|
||||
}
|
||||
|
||||
// CRL methods.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return gnu.java.security.x509.X509CRL.class.getName();
|
||||
}
|
||||
|
||||
public boolean isRevoked(Certificate cert)
|
||||
{
|
||||
if (!(cert instanceof java.security.cert.X509Certificate))
|
||||
throw new IllegalArgumentException("not a X.509 certificate");
|
||||
BigInteger certSerial =
|
||||
((java.security.cert.X509Certificate) cert).getSerialNumber();
|
||||
X509CRLEntry ent = (X509CRLEntry) revokedCerts.get(certSerial);
|
||||
if (ent == null)
|
||||
return false;
|
||||
return ent.getRevocationDate().compareTo(new Date()) < 0;
|
||||
}
|
||||
|
||||
// Own methods.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
private void doVerify(Signature sig, PublicKey key)
|
||||
throws CRLException, InvalidKeyException, SignatureException
|
||||
{
|
||||
sig.initVerify(key);
|
||||
sig.update(tbsCRLBytes);
|
||||
if (!sig.verify(signature))
|
||||
throw new CRLException("signature not verified");
|
||||
}
|
||||
|
||||
private void parse(InputStream in) throws Exception
|
||||
{
|
||||
DERReader der = new DERReader(in);
|
||||
DERValue val = der.read();
|
||||
if (!val.isConstructed())
|
||||
throw new ASN1ParsingException("malformed CertificateList");
|
||||
encoded = val.getEncoded();
|
||||
|
||||
val = der.read();
|
||||
if (!val.isConstructed())
|
||||
throw new ASN1ParsingException("malformed TBSCertList");
|
||||
tbsCRLBytes = val.getEncoded();
|
||||
|
||||
val = der.read();
|
||||
if (val.getValue() instanceof BigInteger)
|
||||
{
|
||||
version = ((BigInteger) val.getValue()).intValue() + 1;
|
||||
val = der.read();
|
||||
}
|
||||
else
|
||||
version = 1;
|
||||
|
||||
if (!val.isConstructed())
|
||||
throw new ASN1ParsingException("malformed AlgorithmIdentifier");
|
||||
DERValue algIdVal = der.read();
|
||||
algId = (OID) algIdVal.getValue();
|
||||
if (val.getLength() > algIdVal.getEncodedLength())
|
||||
{
|
||||
val = der.read();
|
||||
algParams = val.getEncoded();
|
||||
if (val.isConstructed())
|
||||
in.skip(val.getLength());
|
||||
}
|
||||
|
||||
issuerDN = new X500Principal(in);
|
||||
|
||||
thisUpdate = (Date) der.read().getValue();
|
||||
|
||||
val = der.read();
|
||||
if (val.getValue() instanceof Date)
|
||||
{
|
||||
nextUpdate = (Date) val.getValue();
|
||||
val = der.read();
|
||||
}
|
||||
if (val.getTag() != 0)
|
||||
{
|
||||
int len = 0;
|
||||
while (len < val.getLength())
|
||||
{
|
||||
X509CRLEntry entry =
|
||||
new gnu.java.security.x509.X509CRLEntry(version, in);
|
||||
revokedCerts.put(entry.getSerialNumber(), entry);
|
||||
len += entry.getEncoded().length;
|
||||
}
|
||||
}
|
||||
if (version >= 2 && val.getTagClass() != DER.UNIVERSAL && val.getTag() == 0)
|
||||
{
|
||||
val = der.read();
|
||||
int len = 0;
|
||||
while (len < val.getLength())
|
||||
{
|
||||
DERValue ext = der.read();
|
||||
OID extId = (OID) der.read().getValue();
|
||||
DERValue val2 = der.read();
|
||||
Boolean crit = Boolean.valueOf(false);
|
||||
if (val2.getValue() instanceof Boolean)
|
||||
{
|
||||
crit = (Boolean) val2.getValue();
|
||||
val2 = der.read();
|
||||
}
|
||||
byte[] extVal = (byte[]) val2.getValue();
|
||||
extensions.put(extId.toString(), extVal);
|
||||
if (crit.booleanValue())
|
||||
critOids.add(extId.toString());
|
||||
else
|
||||
nonCritOids.add(extId.toString());
|
||||
len += ext.getEncodedLength();
|
||||
}
|
||||
}
|
||||
|
||||
val = der.read();
|
||||
if (!val.isConstructed())
|
||||
throw new ASN1ParsingException("malformed AlgorithmIdentifier");
|
||||
DERValue sigAlgVal = der.read();
|
||||
sigAlg = (OID) sigAlgVal.getValue();
|
||||
if (val.getLength() > sigAlgVal.getEncodedLength())
|
||||
{
|
||||
val = der.read();
|
||||
sigAlgParams = (byte[]) val.getEncoded();
|
||||
if (val.isConstructed())
|
||||
in.skip(val.getLength());
|
||||
}
|
||||
val = der.read();
|
||||
rawSig = val.getEncoded();
|
||||
signature = ((BitString) val.getValue()).toByteArray();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,236 @@
|
||||
/* X509CRLEntry.java -- entry in a X.509 CRL.
|
||||
Copyright (C) 2003 Free Software Foundation, 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.InputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import java.security.cert.CRLException;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import gnu.java.io.ASN1ParsingException;
|
||||
import gnu.java.security.OID;
|
||||
import gnu.java.security.der.DERReader;
|
||||
import gnu.java.security.der.DERValue;
|
||||
import gnu.java.security.der.DERWriter;
|
||||
|
||||
/**
|
||||
* A single entry in a X.509 certificate revocation list.
|
||||
*
|
||||
* @see X509CRL
|
||||
* @author Casey Marshall
|
||||
*/
|
||||
class X509CRLEntry extends java.security.cert.X509CRLEntry
|
||||
{
|
||||
|
||||
// Constants and fields.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/** The DER encoded form of this CRL entry. */
|
||||
private byte[] encoded;
|
||||
|
||||
/** The revoked certificate's serial number. */
|
||||
private BigInteger serialNo;
|
||||
|
||||
/** The date the certificate was revoked. */
|
||||
private Date revocationDate;
|
||||
|
||||
/** The encoded extensions. */
|
||||
private HashMap extensions;
|
||||
|
||||
/** The set of critical extension OIDs. */
|
||||
private HashSet critOids;
|
||||
|
||||
/** the set of non-critical extension OIDs. */
|
||||
private HashSet nonCritOids;
|
||||
|
||||
// Constructor.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Create a new X.509 certificate revocation list entry from the given
|
||||
* input stream and CRL version number.
|
||||
*
|
||||
* @param version The CRL version.
|
||||
* @param encoded The stream of DER bytes.
|
||||
* @throws CRLException If the ASN.1 structure is invalid.
|
||||
* @throws IOException If the bytes cannot be read.
|
||||
*/
|
||||
X509CRLEntry(int version, InputStream encoded)
|
||||
throws CRLException, IOException
|
||||
{
|
||||
super();
|
||||
extensions = new HashMap();
|
||||
critOids = new HashSet();
|
||||
nonCritOids = new HashSet();
|
||||
try
|
||||
{
|
||||
parse(version, encoded);
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
throw ioe;
|
||||
}
|
||||
catch (Exception x)
|
||||
{
|
||||
throw new CRLException(x.toString());
|
||||
}
|
||||
}
|
||||
|
||||
// X509CRLEntry methods.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
return ((X509CRLEntry) o).serialNo.equals(serialNo) &&
|
||||
((X509CRLEntry) o).revocationDate.equals(revocationDate);
|
||||
}
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
return serialNo.hashCode();
|
||||
}
|
||||
|
||||
public byte[] getEncoded() throws CRLException
|
||||
{
|
||||
return (byte[]) encoded.clone();
|
||||
}
|
||||
|
||||
public BigInteger getSerialNumber()
|
||||
{
|
||||
return serialNo;
|
||||
}
|
||||
|
||||
public Date getRevocationDate()
|
||||
{
|
||||
return (Date) revocationDate.clone();
|
||||
}
|
||||
|
||||
public boolean hasExtensions()
|
||||
{
|
||||
return ! extensions.isEmpty();
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return "X509CRLEntry serial=" + serialNo + " revocation date="
|
||||
+ revocationDate + " critExt=" + critOids + " ext=" + nonCritOids;
|
||||
}
|
||||
|
||||
// X509Extension methods.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
public boolean hasUnsupportedCriticalExtension()
|
||||
{
|
||||
return false; // XXX
|
||||
}
|
||||
|
||||
public Set getCriticalExtensionOIDs()
|
||||
{
|
||||
return Collections.unmodifiableSet(critOids);
|
||||
}
|
||||
|
||||
public Set getNonCriticalExtensionOIDs()
|
||||
{
|
||||
return Collections.unmodifiableSet(nonCritOids);
|
||||
}
|
||||
|
||||
public byte[] getExtensionValue(String oid)
|
||||
{
|
||||
byte[] ext = (byte[]) extensions.get(oid);
|
||||
if (ext != null)
|
||||
return (byte[]) ext.clone();
|
||||
return null;
|
||||
}
|
||||
|
||||
// Own methods.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
private void parse(int version, InputStream in) throws Exception
|
||||
{
|
||||
DERReader der = new DERReader(in);
|
||||
DERValue entry = der.read();
|
||||
if (!entry.isConstructed())
|
||||
throw new ASN1ParsingException("malformed revokedCertificate");
|
||||
encoded = entry.getEncoded();
|
||||
int len = 0;
|
||||
DERValue val = der.read();
|
||||
serialNo = (BigInteger) val.getValue();
|
||||
len += DERWriter.definiteEncodingSize(val.getLength())
|
||||
+ val.getLength() + 1;
|
||||
val = der.read();
|
||||
revocationDate = (Date) val.getValue();
|
||||
len += DERWriter.definiteEncodingSize(val.getLength())
|
||||
+ val.getLength() + 1;
|
||||
|
||||
if (len < entry.getLength())
|
||||
{
|
||||
if (version < 2)
|
||||
throw new ASN1ParsingException("extra data in CRL entry");
|
||||
while (len < entry.getLength())
|
||||
{
|
||||
val = der.read();
|
||||
if (!val.isConstructed())
|
||||
throw new ASN1ParsingException("malformed Extension");
|
||||
OID extOid = (OID) der.read().getValue();
|
||||
Boolean critical = Boolean.valueOf(false);
|
||||
DERValue val2 = der.read();
|
||||
if (val2.getValue() instanceof Boolean)
|
||||
{
|
||||
critical = (Boolean) val2.getValue();
|
||||
val2 = der.read();
|
||||
}
|
||||
byte[] ext = (byte[]) val2.getValue();
|
||||
extensions.put(extOid.toString(), ext);
|
||||
if (critical.booleanValue())
|
||||
critOids.add(extOid.toString());
|
||||
else
|
||||
nonCritOids.add(extOid.toString());
|
||||
len += val.getEncodedLength();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,693 @@
|
||||
/* X509Certificate.java -- X.509 certificate.
|
||||
Copyright (C) 2003 Free Software Foundation, 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.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import java.security.AlgorithmParameters;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.security.Principal;
|
||||
import java.security.PublicKey;
|
||||
import java.security.Signature;
|
||||
import java.security.SignatureException;
|
||||
|
||||
import java.security.cert.CertificateEncodingException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateExpiredException;
|
||||
import java.security.cert.CertificateNotYetValidException;
|
||||
import java.security.cert.CertificateParsingException;
|
||||
|
||||
import java.security.spec.DSAParameterSpec;
|
||||
import java.security.spec.DSAPublicKeySpec;
|
||||
import java.security.spec.RSAPublicKeySpec;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.security.auth.x500.X500Principal;
|
||||
|
||||
import gnu.java.io.ASN1ParsingException;
|
||||
import gnu.java.security.OID;
|
||||
import gnu.java.security.der.BitString;
|
||||
import gnu.java.security.der.DER;
|
||||
import gnu.java.security.der.DERReader;
|
||||
import gnu.java.security.der.DERValue;
|
||||
import gnu.java.security.der.DERWriter;
|
||||
|
||||
/**
|
||||
* An implementation of X.509 certificates.
|
||||
*
|
||||
* @author Casey Marshall (rsdio@metastatic.org)
|
||||
*/
|
||||
public class X509Certificate extends java.security.cert.X509Certificate
|
||||
implements Serializable
|
||||
{
|
||||
|
||||
// Constants and fields.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
private static final OID ID_DSA = new OID("1.2.840.10040.4.1");
|
||||
private static final OID ID_DSA_WITH_SHA1 = new OID("1.2.840.10040.4.3");
|
||||
private static final OID ID_RSA = new OID("1.2.840.113549.1.1.1");
|
||||
private static final OID ID_RSA_WITH_MD2 = new OID("1.2.840.113549.1.1.2");
|
||||
private static final OID ID_RSA_WITH_MD5 = new OID("1.2.840.113549.1.1.4");
|
||||
private static final OID ID_RSA_WITH_SHA1 = new OID("1.2.840.113549.1.1.5");
|
||||
|
||||
private static final OID ID_EXTENSION = new OID("2.5.29");
|
||||
private static final OID ID_KEY_USAGE = ID_EXTENSION.getChild(15);
|
||||
private static final OID ID_BASIC_CONSTRAINTS = ID_EXTENSION.getChild(19);
|
||||
private static final OID ID_EXT_KEY_USAGE = ID_EXTENSION.getChild(37);
|
||||
|
||||
private static final int OTHER_NAME = 0;
|
||||
private static final int RFC882_NAME = 1;
|
||||
private static final int DNS_NAME = 2;
|
||||
private static final int X400_ADDRESS = 3;
|
||||
private static final int DIRECTORY_NAME = 4;
|
||||
private static final int EDI_PARTY_NAME = 5;
|
||||
private static final int URI = 6;
|
||||
private static final int IP_ADDRESS = 7;
|
||||
private static final int REGISTERED_ID = 8;
|
||||
|
||||
// This object SHOULD be serialized with an instance of
|
||||
// java.security.cert.Certificate.CertificateRep, thus all fields are
|
||||
// transient.
|
||||
|
||||
// The encoded certificate.
|
||||
private transient byte[] encoded;
|
||||
|
||||
// TBSCertificate part.
|
||||
private transient byte[] tbsCertBytes;
|
||||
private transient int version;
|
||||
private transient BigInteger serialNo;
|
||||
private transient OID algId;
|
||||
private transient byte[] algVal;
|
||||
private transient X500Principal issuer;
|
||||
private transient Date notBefore;
|
||||
private transient Date notAfter;
|
||||
private transient X500Principal subject;
|
||||
private transient PublicKey subjectKey;
|
||||
private transient BitString issuerUniqueId;
|
||||
private transient BitString subjectUniqueId;
|
||||
private transient HashMap extensions;
|
||||
private transient HashSet critOids;
|
||||
private transient HashSet nonCritOids;
|
||||
|
||||
private transient BitString keyUsage;
|
||||
private transient int basicConstraints = -1;
|
||||
|
||||
// Signature.
|
||||
private transient OID sigAlgId;
|
||||
private transient byte[] sigAlgVal;
|
||||
private transient byte[] signature;
|
||||
|
||||
// Constructors.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Create a new X.509 certificate from the encoded data. The input
|
||||
* data are expected to be the ASN.1 DER encoding of the certificate.
|
||||
*
|
||||
* @param encoded The encoded certificate data.
|
||||
* @throws IOException If the certificate cannot be read, possibly
|
||||
* from a formatting error.
|
||||
* @throws CertificateException If the data read is not an X.509
|
||||
* certificate.
|
||||
*/
|
||||
public X509Certificate(InputStream encoded)
|
||||
throws CertificateException, IOException
|
||||
{
|
||||
super();
|
||||
extensions = new HashMap();
|
||||
critOids = new HashSet();
|
||||
nonCritOids = new HashSet();
|
||||
try
|
||||
{
|
||||
parse(encoded);
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
throw ioe;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new CertificateException(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
// X509Certificate methods.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
public void checkValidity()
|
||||
throws CertificateExpiredException, CertificateNotYetValidException
|
||||
{
|
||||
checkValidity(new Date());
|
||||
}
|
||||
|
||||
public void checkValidity(Date date)
|
||||
throws CertificateExpiredException, CertificateNotYetValidException
|
||||
{
|
||||
if (date.compareTo(notBefore) < 0)
|
||||
throw new CertificateNotYetValidException();
|
||||
if (date.compareTo(notAfter) > 0)
|
||||
throw new CertificateExpiredException();
|
||||
}
|
||||
|
||||
public int getVersion()
|
||||
{
|
||||
return version;
|
||||
}
|
||||
|
||||
public BigInteger getSerialNumber()
|
||||
{
|
||||
return serialNo;
|
||||
}
|
||||
|
||||
public Principal getIssuerDN()
|
||||
{
|
||||
return getIssuerX500Principal();
|
||||
}
|
||||
|
||||
public X500Principal getIssuerX500Principal()
|
||||
{
|
||||
return issuer;
|
||||
}
|
||||
|
||||
public Principal getSubjectDN()
|
||||
{
|
||||
return getSubjectX500Principal();
|
||||
}
|
||||
|
||||
public X500Principal getSubjectX500Principal()
|
||||
{
|
||||
return subject;
|
||||
}
|
||||
|
||||
public Date getNotBefore()
|
||||
{
|
||||
return (Date) notBefore.clone();
|
||||
}
|
||||
|
||||
public Date getNotAfter()
|
||||
{
|
||||
return (Date) notAfter.clone();
|
||||
}
|
||||
|
||||
public byte[] getTBSCertificate() throws CertificateEncodingException
|
||||
{
|
||||
return (byte[]) tbsCertBytes.clone();
|
||||
}
|
||||
|
||||
public byte[] getSignature()
|
||||
{
|
||||
return (byte[]) signature.clone();
|
||||
}
|
||||
|
||||
public String getSigAlgName()
|
||||
{
|
||||
if (sigAlgId.equals(ID_DSA_WITH_SHA1))
|
||||
return "SHA1withDSA";
|
||||
if (sigAlgId.equals(ID_RSA_WITH_MD2 ))
|
||||
return "MD2withRSA";
|
||||
if (sigAlgId.equals(ID_RSA_WITH_MD5 ))
|
||||
return "MD5withRSA";
|
||||
if (sigAlgId.equals(ID_RSA_WITH_SHA1 ))
|
||||
return "SHA1withRSA";
|
||||
return "unknown";
|
||||
// return sigAlgId.getShortName();
|
||||
}
|
||||
|
||||
public String getSigAlgOID()
|
||||
{
|
||||
return sigAlgId.toString();
|
||||
}
|
||||
|
||||
public byte[] getSigAlgParams()
|
||||
{
|
||||
return (byte[]) sigAlgVal.clone();
|
||||
}
|
||||
|
||||
public boolean[] getIssuerUniqueID()
|
||||
{
|
||||
if (issuerUniqueId != null)
|
||||
return issuerUniqueId.toBooleanArray();
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean[] getSubjectUniqueID()
|
||||
{
|
||||
if (subjectUniqueId != null)
|
||||
return subjectUniqueId.toBooleanArray();
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean[] getKeyUsage()
|
||||
{
|
||||
if (keyUsage != null)
|
||||
return keyUsage.toBooleanArray();
|
||||
return null;
|
||||
}
|
||||
|
||||
public List getExtendedKeyUsage() throws CertificateParsingException
|
||||
{
|
||||
byte[] ext = (byte[]) extensions.get("2.5.29.37");
|
||||
if (ext == null)
|
||||
return null;
|
||||
LinkedList usages = new LinkedList();
|
||||
try
|
||||
{
|
||||
DERReader der = new DERReader(new ByteArrayInputStream(ext));
|
||||
DERValue seq = der.read();
|
||||
if (!seq.isConstructed())
|
||||
throw new CertificateParsingException();
|
||||
int len = 0;
|
||||
while (len < seq.getLength())
|
||||
{
|
||||
DERValue oid = der.read();
|
||||
if (!(oid.getValue() instanceof OID))
|
||||
throw new CertificateParsingException();
|
||||
usages.add(oid.getValue().toString());
|
||||
len += DERWriter.definiteEncodingSize(oid.getLength())
|
||||
+ oid.getLength() + 1;
|
||||
}
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
throw new CertificateParsingException();
|
||||
}
|
||||
return usages;
|
||||
}
|
||||
|
||||
public int getBasicConstraints()
|
||||
{
|
||||
return basicConstraints;
|
||||
}
|
||||
|
||||
public Collection getSubjectAlternativeNames()
|
||||
throws CertificateParsingException
|
||||
{
|
||||
byte[] ext = getExtensionValue("2.5.29.17");
|
||||
if (ext == null)
|
||||
return null;
|
||||
return getAltNames(ext);
|
||||
}
|
||||
|
||||
public Collection getIssuerAlternativeNames()
|
||||
throws CertificateParsingException
|
||||
{
|
||||
byte[] ext = getExtensionValue("2.5.29.18");
|
||||
if (ext == null)
|
||||
return null;
|
||||
return getAltNames(ext);
|
||||
}
|
||||
|
||||
// X509Extension methods.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
public boolean hasUnsupportedCriticalExtension()
|
||||
{
|
||||
for (Iterator it = critOids.iterator(); it.hasNext(); )
|
||||
{
|
||||
String oid = (String) it.next();
|
||||
if (!oid.equals("2.5.29.15") && !oid.equals("2.5.29.17") &&
|
||||
!oid.equals("2.5.29.18") && !oid.equals("2.5.29.19") &&
|
||||
!oid.equals("2.5.29.37"))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public Set getCriticalExtensionOIDs()
|
||||
{
|
||||
return Collections.unmodifiableSet(critOids);
|
||||
}
|
||||
|
||||
public Set getNonCriticalExtensionOIDs()
|
||||
{
|
||||
return Collections.unmodifiableSet(nonCritOids);
|
||||
}
|
||||
|
||||
public byte[] getExtensionValue(String oid)
|
||||
{
|
||||
byte[] ext = (byte[]) extensions.get(oid);
|
||||
if (ext != null)
|
||||
return (byte[]) ext.clone();
|
||||
return null;
|
||||
}
|
||||
|
||||
// Certificate methods.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
public byte[] getEncoded() throws CertificateEncodingException
|
||||
{
|
||||
return (byte[]) encoded.clone();
|
||||
}
|
||||
|
||||
public void verify(PublicKey key)
|
||||
throws CertificateException, NoSuchAlgorithmException,
|
||||
InvalidKeyException, NoSuchProviderException, SignatureException
|
||||
{
|
||||
Signature sig = Signature.getInstance(sigAlgId.toString());
|
||||
doVerify(sig, key);
|
||||
}
|
||||
|
||||
public void verify(PublicKey key, String provider)
|
||||
throws CertificateException, NoSuchAlgorithmException,
|
||||
InvalidKeyException, NoSuchProviderException, SignatureException
|
||||
{
|
||||
Signature sig = Signature.getInstance(sigAlgId.toString(), provider);
|
||||
doVerify(sig, key);
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
// XXX say more than this.
|
||||
return gnu.java.security.x509.X509Certificate.class.getName();
|
||||
}
|
||||
|
||||
public PublicKey getPublicKey()
|
||||
{
|
||||
return subjectKey;
|
||||
}
|
||||
|
||||
public Object writeReplace() throws java.io.ObjectStreamException
|
||||
{
|
||||
return super.writeReplace();
|
||||
}
|
||||
|
||||
// Own methods.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Verify this certificate's signature.
|
||||
*/
|
||||
private void doVerify(Signature sig, PublicKey key)
|
||||
throws CertificateException, InvalidKeyException, SignatureException
|
||||
{
|
||||
sig.initVerify(key);
|
||||
sig.update(tbsCertBytes);
|
||||
if (!sig.verify(signature))
|
||||
throw new CertificateException("signature not validated");
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a GeneralNames structure.
|
||||
*/
|
||||
private List getAltNames(byte[] encoded)
|
||||
throws CertificateParsingException
|
||||
{
|
||||
LinkedList names = new LinkedList();
|
||||
try
|
||||
{
|
||||
ByteArrayInputStream in = new ByteArrayInputStream(encoded);
|
||||
DERReader der = new DERReader(in);
|
||||
DERValue seq = der.read();
|
||||
if (!seq.isConstructed())
|
||||
throw new CertificateParsingException();
|
||||
int len = 0;
|
||||
while (len < seq.getLength())
|
||||
{
|
||||
DERValue name = der.read();
|
||||
ArrayList pair = new ArrayList(2);
|
||||
Object nameVal = null;
|
||||
switch (name.getTag())
|
||||
{
|
||||
case RFC882_NAME:
|
||||
case DNS_NAME:
|
||||
case URI:
|
||||
nameVal = new String((byte[]) name.getValue());
|
||||
break;
|
||||
case IP_ADDRESS:
|
||||
nameVal = java.net.InetAddress.getByAddress(
|
||||
(byte[]) name.getValue()).getHostAddress();
|
||||
break;
|
||||
case REGISTERED_ID:
|
||||
nameVal = new OID((byte[]) name.getValue());
|
||||
break;
|
||||
case OTHER_NAME:
|
||||
case X400_ADDRESS:
|
||||
case DIRECTORY_NAME:
|
||||
case EDI_PARTY_NAME:
|
||||
nameVal = name.getEncoded();
|
||||
break;
|
||||
default:
|
||||
throw new CertificateParsingException();
|
||||
}
|
||||
pair.add(new Integer(name.getTag()));
|
||||
pair.add(nameVal);
|
||||
names.add(pair);
|
||||
if (name.isConstructed())
|
||||
in.skip(name.getLength());
|
||||
len += name.getEncodedLength();
|
||||
}
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
throw new CertificateParsingException(ioe.toString());
|
||||
}
|
||||
return Collections.unmodifiableList(names);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a DER stream into an X.509 certificate.
|
||||
*
|
||||
* @param encoded The encoded bytes.
|
||||
*/
|
||||
private void parse(InputStream encoded) throws Exception
|
||||
{
|
||||
DERReader der = new DERReader(encoded);
|
||||
|
||||
// Certificate ::= SEQUENCE {
|
||||
DERValue cert = der.read();
|
||||
this.encoded = cert.getEncoded();
|
||||
if (!cert.isConstructed())
|
||||
throw new ASN1ParsingException("malformed Certificate");
|
||||
|
||||
// TBSCertificate ::= SEQUENCE {
|
||||
DERValue tbsCert = der.read();
|
||||
if (tbsCert.getValue() != DER.CONSTRUCTED_VALUE)
|
||||
throw new ASN1ParsingException("malformed TBSCertificate");
|
||||
tbsCertBytes = tbsCert.getEncoded();
|
||||
|
||||
DERValue val = der.read();
|
||||
if (val.getTagClass() == DER.CONTEXT && val.getTag() == 0)
|
||||
{
|
||||
// Version ::= INTEGER [0] { v1(0), v2(1), v3(2) }
|
||||
version = ((BigInteger) der.read().getValue()).intValue() + 1;
|
||||
val = der.read();
|
||||
}
|
||||
else
|
||||
{
|
||||
version = 1;
|
||||
}
|
||||
// SerialNumber ::= INTEGER
|
||||
serialNo = (BigInteger) val.getValue();
|
||||
|
||||
// AlgorithmIdentifier ::= SEQUENCE {
|
||||
val = der.read();
|
||||
if (!val.isConstructed())
|
||||
throw new ASN1ParsingException("malformed AlgorithmIdentifier");
|
||||
int certAlgLen = val.getLength();
|
||||
val = der.read();
|
||||
algId = (OID) val.getValue();
|
||||
if (certAlgLen > val.getEncodedLength())
|
||||
{
|
||||
val = der.read();
|
||||
if (val == null)
|
||||
algVal = null;
|
||||
else
|
||||
algVal = val.getEncoded();
|
||||
if (val.isConstructed())
|
||||
encoded.skip(val.getLength());
|
||||
}
|
||||
|
||||
issuer = new X500Principal(encoded);
|
||||
|
||||
if (!der.read().isConstructed())
|
||||
throw new ASN1ParsingException("malformed Validity");
|
||||
notBefore = (Date) der.read().getValue();
|
||||
notAfter = (Date) der.read().getValue();
|
||||
|
||||
subject = new X500Principal(encoded);
|
||||
|
||||
if (!der.read().isConstructed())
|
||||
throw new ASN1ParsingException("malformed SubjectPublicKeyInfo");
|
||||
|
||||
val = der.read();
|
||||
if (!val.isConstructed())
|
||||
throw new ASN1ParsingException("malformed AlgorithmIdentifier");
|
||||
int keyAlgLen = val.getLength();
|
||||
val = der.read();
|
||||
OID keyID = (OID) val.getValue();
|
||||
byte[] keyParams = null;
|
||||
if (keyAlgLen > val.getEncodedLength())
|
||||
{
|
||||
val = der.read();
|
||||
keyParams = val.getEncoded();
|
||||
if (algVal == null)
|
||||
algVal = keyParams;
|
||||
if (val.isConstructed())
|
||||
encoded.skip(val.getLength());
|
||||
}
|
||||
val = der.read();
|
||||
byte[] keyVal = ((BitString) val.getValue()).toByteArray();
|
||||
|
||||
if (keyID.equals(ID_DSA))
|
||||
{
|
||||
AlgorithmParameters params = AlgorithmParameters.getInstance("DSA");
|
||||
params.init(keyParams, "ASN.1");
|
||||
KeyFactory keyFac = KeyFactory.getInstance("DSA");
|
||||
DSAParameterSpec spec = (DSAParameterSpec)
|
||||
params.getParameterSpec(DSAParameterSpec.class);
|
||||
subjectKey = keyFac.generatePublic(new DSAPublicKeySpec(
|
||||
(BigInteger) new DERReader(keyVal).read().getValue(),
|
||||
spec.getP(), spec.getQ(), spec.getG()));
|
||||
}
|
||||
else if (keyID.equals(ID_RSA))
|
||||
{
|
||||
KeyFactory keyFac = KeyFactory.getInstance("RSA");
|
||||
DERReader rsaKey = new DERReader(keyVal);
|
||||
if (!rsaKey.read().isConstructed())
|
||||
throw new ASN1ParsingException("malformed RSAPublicKey");
|
||||
subjectKey = keyFac.generatePublic(new RSAPublicKeySpec(
|
||||
(BigInteger) rsaKey.read().getValue(),
|
||||
(BigInteger) rsaKey.read().getValue()));
|
||||
}
|
||||
else
|
||||
throw new ASN1ParsingException("unknown key algorithm " + keyID);
|
||||
|
||||
if (version > 1)
|
||||
val = der.read();
|
||||
if (version >= 2 && val.getTagClass() != DER.UNIVERSAL && val.getTag() == 1)
|
||||
{
|
||||
byte[] b = (byte[]) val.getValue();
|
||||
issuerUniqueId = new BitString(b, 1, b.length-1, b[0] & 0xFF);
|
||||
val = der.read();
|
||||
}
|
||||
if (version >= 2 && val.getTagClass() != DER.UNIVERSAL && val.getTag() == 2)
|
||||
{
|
||||
byte[] b = (byte[]) val.getValue();
|
||||
subjectUniqueId = new BitString(b, 1, b.length-1, b[0] & 0xFF);
|
||||
val = der.read();
|
||||
}
|
||||
if (version >= 3 && val.getTagClass() != DER.UNIVERSAL && val.getTag() == 3)
|
||||
{
|
||||
val = der.read();
|
||||
int len = 0;
|
||||
while (len < val.getLength())
|
||||
{
|
||||
DERValue ext = der.read();
|
||||
OID extId = (OID) der.read().getValue();
|
||||
DERValue val2 = der.read();
|
||||
Boolean crit = Boolean.valueOf(false);
|
||||
if (val2.getValue() instanceof Boolean)
|
||||
{
|
||||
crit = (Boolean) val2.getValue();
|
||||
val2 = der.read();
|
||||
}
|
||||
byte[] extVal = (byte[]) val2.getValue();
|
||||
extensions.put(extId.toString(), extVal);
|
||||
if (crit.booleanValue())
|
||||
critOids.add(extId.toString());
|
||||
else
|
||||
nonCritOids.add(extId.toString());
|
||||
if (extId.equals(ID_KEY_USAGE))
|
||||
{
|
||||
keyUsage = (BitString) DERReader.read(extVal).getValue();
|
||||
}
|
||||
else if (extId.equals(ID_BASIC_CONSTRAINTS))
|
||||
{
|
||||
DERReader bc = new DERReader(extVal);
|
||||
DERValue constraints = bc.read();
|
||||
if (!constraints.isConstructed())
|
||||
throw new ASN1ParsingException("malformed BasicConstraints");
|
||||
if (constraints.getLength() > 0)
|
||||
{
|
||||
boolean ca = false;
|
||||
int constr = -1;
|
||||
val2 = bc.read();
|
||||
if (val2.getValue() instanceof Boolean)
|
||||
{
|
||||
ca = ((Boolean) val2.getValue()).booleanValue();
|
||||
if (constraints.getLength() > val2.getEncodedLength())
|
||||
val2 = bc.read();
|
||||
}
|
||||
if (val2.getValue() instanceof BigInteger)
|
||||
constr = ((BigInteger) val2.getValue()).intValue();
|
||||
basicConstraints = constr;
|
||||
}
|
||||
}
|
||||
len += ext.getEncodedLength();
|
||||
}
|
||||
}
|
||||
|
||||
val = der.read();
|
||||
if (!val.isConstructed())
|
||||
throw new ASN1ParsingException("malformed AlgorithmIdentifier");
|
||||
int sigAlgLen = val.getLength();
|
||||
val = der.read();
|
||||
sigAlgId = (OID) val.getValue();
|
||||
if (sigAlgLen > val.getEncodedLength())
|
||||
{
|
||||
val = der.read();
|
||||
if (val.getValue() == null)
|
||||
sigAlgVal = keyParams;
|
||||
else
|
||||
sigAlgVal = (byte[]) val.getEncoded();
|
||||
if (val.isConstructed())
|
||||
encoded.skip(val.getLength());
|
||||
}
|
||||
signature = ((BitString) der.read().getValue()).toByteArray();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user