feat(jdk8): move files to new folder to avoid resources compiled.

This commit is contained in:
2025-09-07 15:25:52 +08:00
parent 3f0047bf6f
commit 8c35cfb1c0
17415 changed files with 217 additions and 213 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,118 @@
/*
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import sun.security.util.*;
/**
* @author Ram Marti
*/
public final class AccessDescription {
private int myhash = -1;
private ObjectIdentifier accessMethod;
private GeneralName accessLocation;
public static final ObjectIdentifier Ad_OCSP_Id =
ObjectIdentifier.newInternal(new int[] {1, 3, 6, 1, 5, 5, 7, 48, 1});
public static final ObjectIdentifier Ad_CAISSUERS_Id =
ObjectIdentifier.newInternal(new int[] {1, 3, 6, 1, 5, 5, 7, 48, 2});
public static final ObjectIdentifier Ad_TIMESTAMPING_Id =
ObjectIdentifier.newInternal(new int[] {1, 3, 6, 1, 5, 5, 7, 48, 3});
public static final ObjectIdentifier Ad_CAREPOSITORY_Id =
ObjectIdentifier.newInternal(new int[] {1, 3, 6, 1, 5, 5, 7, 48, 5});
public AccessDescription(ObjectIdentifier accessMethod, GeneralName accessLocation) {
this.accessMethod = accessMethod;
this.accessLocation = accessLocation;
}
public AccessDescription(DerValue derValue) throws IOException {
DerInputStream derIn = derValue.getData();
accessMethod = derIn.getOID();
accessLocation = new GeneralName(derIn.getDerValue());
}
public ObjectIdentifier getAccessMethod() {
return accessMethod;
}
public GeneralName getAccessLocation() {
return accessLocation;
}
public void encode(DerOutputStream out) throws IOException {
DerOutputStream tmp = new DerOutputStream();
tmp.putOID(accessMethod);
accessLocation.encode(tmp);
out.write(DerValue.tag_Sequence, tmp);
}
public int hashCode() {
if (myhash == -1) {
myhash = accessMethod.hashCode() + accessLocation.hashCode();
}
return myhash;
}
public boolean equals(Object obj) {
if (obj == null || (!(obj instanceof AccessDescription))) {
return false;
}
AccessDescription that = (AccessDescription)obj;
if (this == that) {
return true;
}
return (accessMethod.equals((Object)that.getAccessMethod()) &&
accessLocation.equals(that.getAccessLocation()));
}
public String toString() {
String method = null;
if (accessMethod.equals((Object)Ad_CAISSUERS_Id)) {
method = "caIssuers";
} else if (accessMethod.equals((Object)Ad_CAREPOSITORY_Id)) {
method = "caRepository";
} else if (accessMethod.equals((Object)Ad_TIMESTAMPING_Id)) {
method = "timeStamping";
} else if (accessMethod.equals((Object)Ad_OCSP_Id)) {
method = "ocsp";
} else {
method = accessMethod.toString();
}
return ("\n accessMethod: " + method +
"\n accessLocation: " + accessLocation.toString() + "\n");
}
}

View File

@@ -0,0 +1,225 @@
/*
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.math.BigInteger;
import java.security.*;
import java.security.interfaces.DSAParams;
import sun.security.util.*;
/**
* This class identifies DSS/DSA Algorithm variants, which are distinguished
* by using different algorithm parameters <em>P, Q, G</em>. It uses the
* NIST/IETF standard DER encoding. These are used to implement the Digital
* Signature Standard (DSS), FIPS 186.
*
* <P><em><b>NOTE:</b> DSS/DSA Algorithm IDs may be created without these
* parameters. Use of DSS/DSA in modes where parameters are
* either implicit (e.g. a default applicable to a site or a larger scope),
* or are derived from some Certificate Authority's DSS certificate, is
* not supported directly. The application is responsible for creating a key
* containing the required parameters prior to using the key in cryptographic
* operations. The follwoing is an example of how this may be done assuming
* that we have a certificate called <code>currentCert</code> which doesn't
* contain DSS/DSA parameters and we need to derive DSS/DSA parameters
* from a CA's certificate called <code>caCert</code>.
* <p>
* <code><pre>
* // key containing parameters to use
* DSAPublicKey cAKey = (DSAPublicKey)(caCert.getPublicKey());
* // key without parameters
* DSAPublicKey nullParamsKey = (DSAPublicKey)(currentCert.getPublicKey());
*
* DSAParams cAKeyParams = cAKey.getParams();
* KeyFactory kf = KeyFactory.getInstance("DSA");
* DSAPublicKeySpec ks = new DSAPublicKeySpec(nullParamsKey.getY(),
* cAKeyParams.getP(),
* cAKeyParams.getQ(),
* cAKeyParams.getG());
* DSAPublicKey usableKey = kf.generatePublic(ks);
* </pre></code>
*
* @see java.security.interfaces.DSAParams
* @see java.security.interfaces.DSAPublicKey
* @see java.security.KeyFactory
* @see java.security.spec.DSAPublicKeySpec
*
* @author David Brownell
*/
public final
class AlgIdDSA extends AlgorithmId implements DSAParams
{
private static final long serialVersionUID = 3437177836797504046L;
/*
* The three unsigned integer parameters.
*/
private BigInteger p , q, g;
/** Returns the DSS/DSA parameter "P" */
public BigInteger getP () { return p; }
/** Returns the DSS/DSA parameter "Q" */
public BigInteger getQ () { return q; }
/** Returns the DSS/DSA parameter "G" */
public BigInteger getG () { return g; }
/**
* Default constructor. The OID and parameters must be
* deserialized before this algorithm ID is used.
*/
@Deprecated
public AlgIdDSA () {}
AlgIdDSA (DerValue val) throws IOException
{ super(val.getOID()); }
/**
* Construct an AlgIdDSA from an X.509 encoded byte array.
*/
public AlgIdDSA (byte[] encodedAlg) throws IOException
{ super (new DerValue(encodedAlg).getOID()); }
/**
* Constructs a DSS/DSA Algorithm ID from unsigned integers that
* define the algorithm parameters. Those integers are encoded
* as big-endian byte arrays.
*
* @param p the DSS/DSA parameter "P"
* @param q the DSS/DSA parameter "Q"
* @param g the DSS/DSA parameter "G"
*/
public AlgIdDSA (byte p [], byte q [], byte g [])
throws IOException
{
this (new BigInteger (1, p),
new BigInteger (1, q),
new BigInteger (1, g));
}
/**
* Constructs a DSS/DSA Algorithm ID from numeric parameters.
* If all three are null, then the parameters portion of the algorithm id
* is set to null. See note in header regarding use.
*
* @param p the DSS/DSA parameter "P"
* @param q the DSS/DSA parameter "Q"
* @param g the DSS/DSA parameter "G"
*/
public AlgIdDSA (BigInteger p, BigInteger q, BigInteger g)
{
super (DSA_oid);
if (p != null || q != null || g != null) {
if (p == null || q == null || g == null)
throw new ProviderException("Invalid parameters for DSS/DSA" +
" Algorithm ID");
try {
this.p = p;
this.q = q;
this.g = g;
initializeParams ();
} catch (IOException e) {
/* this should not happen */
throw new ProviderException ("Construct DSS/DSA Algorithm ID");
}
}
}
/**
* Returns "DSA", indicating the Digital Signature Algorithm (DSA) as
* defined by the Digital Signature Standard (DSS), FIPS 186.
*/
public String getName ()
{ return "DSA"; }
/*
* For algorithm IDs which haven't been created from a DER encoded
* value, "params" must be created.
*/
private void initializeParams ()
throws IOException
{
DerOutputStream out = new DerOutputStream ();
out.putInteger(p);
out.putInteger(q);
out.putInteger(g);
params = new DerValue (DerValue.tag_Sequence,out.toByteArray ());
}
/**
* Parses algorithm parameters P, Q, and G. They're found
* in the "params" member, which never needs to be changed.
*/
protected void decodeParams ()
throws IOException
{
if (params == null)
throw new IOException("DSA alg params are null");
if (params.tag != DerValue.tag_Sequence)
throw new IOException("DSA alg parsing error");
params.data.reset ();
this.p = params.data.getBigInteger();
this.q = params.data.getBigInteger();
this.g = params.data.getBigInteger();
if (params.data.available () != 0)
throw new IOException ("AlgIdDSA params, extra="+
params.data.available ());
}
/*
* Returns a formatted string describing the parameters.
*/
public String toString ()
{ return paramsToString (); }
/*
* Returns a string describing the parameters.
*/
protected String paramsToString ()
{
if (params == null)
return " null\n";
else
return
"\n p:\n" + Debug.toHexString(p) +
"\n q:\n" + Debug.toHexString(q) +
"\n g:\n" + Debug.toHexString(g) +
"\n";
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,49 @@
/*
* Copyright (c) 1997, 2003, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.util.Vector;
import java.util.Enumeration;
/**
* <p>This class provides the Enumeration implementation used
* by all the X509 certificate attributes to return the attribute
* names contained within them.
*
* @author Amit Kapoor
* @author Hemma Prafullchandra
*/
public class AttributeNameEnumeration extends Vector<String> {
private static final long serialVersionUID = -6067440240757099134L;
/**
* The default constructor for this class.
*/
public AttributeNameEnumeration() {
super(4,2);
}
}

View File

@@ -0,0 +1,241 @@
/*
* Copyright (c) 2004, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.io.OutputStream;
import java.util.*;
import sun.security.util.DerOutputStream;
import sun.security.util.DerValue;
/**
* The Authority Information Access Extension (OID = 1.3.6.1.5.5.7.1.1).
* <p>
* The AIA extension identifies how to access CA information and services
* for the certificate in which it appears. It enables CAs to issue their
* certificates pre-configured with the URLs appropriate for contacting
* services relevant to those certificates. For example, a CA may issue a
* certificate that identifies the specific OCSP Responder to use when
* performing on-line validation of that certificate.
* <p>
* This extension is defined in <a href="http://tools.ietf.org/html/rfc5280">
* Internet X.509 PKI Certificate and Certificate Revocation List
* (CRL) Profile</a>. The profile permits
* the extension to be included in end-entity or CA certificates,
* and it must be marked as non-critical. Its ASN.1 definition is as follows:
* <pre>
* id-pe-authorityInfoAccess OBJECT IDENTIFIER ::= { id-pe 1 }
*
* AuthorityInfoAccessSyntax ::=
* SEQUENCE SIZE (1..MAX) OF AccessDescription
*
* AccessDescription ::= SEQUENCE {
* accessMethod OBJECT IDENTIFIER,
* accessLocation GeneralName }
* </pre>
* <p>
* @see Extension
* @see CertAttrSet
*/
public class AuthorityInfoAccessExtension extends Extension
implements CertAttrSet<String> {
/**
* Identifier for this attribute, to be used with the
* get, set, delete methods of Certificate, x509 type.
*/
public static final String IDENT =
"x509.info.extensions.AuthorityInfoAccess";
/**
* Attribute name.
*/
public static final String NAME = "AuthorityInfoAccess";
public static final String DESCRIPTIONS = "descriptions";
/**
* The List of AccessDescription objects.
*/
private List<AccessDescription> accessDescriptions;
/**
* Create an AuthorityInfoAccessExtension from a List of
* AccessDescription; the criticality is set to false.
*
* @param accessDescriptions the List of AccessDescription
* @throws IOException on error
*/
public AuthorityInfoAccessExtension(
List<AccessDescription> accessDescriptions) throws IOException {
this.extensionId = PKIXExtensions.AuthInfoAccess_Id;
this.critical = false;
this.accessDescriptions = accessDescriptions;
encodeThis();
}
/**
* Create the extension from the passed DER encoded value of the same.
*
* @param critical true if the extension is to be treated as critical.
* @param value Array of DER encoded bytes of the actual value.
* @exception IOException on error.
*/
public AuthorityInfoAccessExtension(Boolean critical, Object value)
throws IOException {
this.extensionId = PKIXExtensions.AuthInfoAccess_Id;
this.critical = critical.booleanValue();
if (!(value instanceof byte[])) {
throw new IOException("Illegal argument type");
}
extensionValue = (byte[])value;
DerValue val = new DerValue(extensionValue);
if (val.tag != DerValue.tag_Sequence) {
throw new IOException("Invalid encoding for " +
"AuthorityInfoAccessExtension.");
}
accessDescriptions = new ArrayList<AccessDescription>();
while (val.data.available() != 0) {
DerValue seq = val.data.getDerValue();
AccessDescription accessDescription = new AccessDescription(seq);
accessDescriptions.add(accessDescription);
}
}
/**
* Return the list of AccessDescription objects.
*/
public List<AccessDescription> getAccessDescriptions() {
return accessDescriptions;
}
/**
* Return the name of this attribute.
*/
public String getName() {
return NAME;
}
/**
* Write the extension to the DerOutputStream.
*
* @param out the DerOutputStream to write the extension to.
* @exception IOException on encoding errors.
*/
public void encode(OutputStream out) throws IOException {
DerOutputStream tmp = new DerOutputStream();
if (this.extensionValue == null) {
this.extensionId = PKIXExtensions.AuthInfoAccess_Id;
this.critical = false;
encodeThis();
}
super.encode(tmp);
out.write(tmp.toByteArray());
}
/**
* Set the attribute value.
*/
@SuppressWarnings("unchecked") // Checked with an instanceof check
public void set(String name, Object obj) throws IOException {
if (name.equalsIgnoreCase(DESCRIPTIONS)) {
if (!(obj instanceof List)) {
throw new IOException("Attribute value should be of type List.");
}
accessDescriptions = (List<AccessDescription>)obj;
} else {
throw new IOException("Attribute name [" + name +
"] not recognized by " +
"CertAttrSet:AuthorityInfoAccessExtension.");
}
encodeThis();
}
/**
* Get the attribute value.
*/
public List<AccessDescription> get(String name) throws IOException {
if (name.equalsIgnoreCase(DESCRIPTIONS)) {
return accessDescriptions;
} else {
throw new IOException("Attribute name [" + name +
"] not recognized by " +
"CertAttrSet:AuthorityInfoAccessExtension.");
}
}
/**
* Delete the attribute value.
*/
public void delete(String name) throws IOException {
if (name.equalsIgnoreCase(DESCRIPTIONS)) {
accessDescriptions = new ArrayList<AccessDescription>();
} else {
throw new IOException("Attribute name [" + name +
"] not recognized by " +
"CertAttrSet:AuthorityInfoAccessExtension.");
}
encodeThis();
}
/**
* Return an enumeration of names of attributes existing within this
* attribute.
*/
public Enumeration<String> getElements() {
AttributeNameEnumeration elements = new AttributeNameEnumeration();
elements.addElement(DESCRIPTIONS);
return elements.elements();
}
// Encode this extension value
private void encodeThis() throws IOException {
if (accessDescriptions.isEmpty()) {
this.extensionValue = null;
} else {
DerOutputStream ads = new DerOutputStream();
for (AccessDescription accessDescription : accessDescriptions) {
accessDescription.encode(ads);
}
DerOutputStream seq = new DerOutputStream();
seq.write(DerValue.tag_Sequence, ads);
this.extensionValue = seq.toByteArray();
}
}
/**
* Return the extension as user readable string.
*/
public String toString() {
return super.toString() + "AuthorityInfoAccess [\n "
+ accessDescriptions + "\n]\n";
}
}

View File

@@ -0,0 +1,322 @@
/*
* Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Enumeration;
import sun.security.util.*;
/**
* This class represents the Authority Key Identifier Extension.
*
* <p>The authority key identifier extension provides a means of
* identifying the particular public key used to sign a certificate.
* This extension would be used where an issuer has multiple signing
* keys (either due to multiple concurrent key pairs or due to
* changeover).
* <p>
* The ASN.1 syntax for this is:
* <pre>
* AuthorityKeyIdentifier ::= SEQUENCE {
* keyIdentifier [0] KeyIdentifier OPTIONAL,
* authorityCertIssuer [1] GeneralNames OPTIONAL,
* authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL
* }
* KeyIdentifier ::= OCTET STRING
* </pre>
* @author Amit Kapoor
* @author Hemma Prafullchandra
* @see Extension
* @see CertAttrSet
*/
public class AuthorityKeyIdentifierExtension extends Extension
implements CertAttrSet<String> {
/**
* Identifier for this attribute, to be used with the
* get, set, delete methods of Certificate, x509 type.
*/
public static final String IDENT =
"x509.info.extensions.AuthorityKeyIdentifier";
/**
* Attribute names.
*/
public static final String NAME = "AuthorityKeyIdentifier";
public static final String KEY_ID = "key_id";
public static final String AUTH_NAME = "auth_name";
public static final String SERIAL_NUMBER = "serial_number";
// Private data members
private static final byte TAG_ID = 0;
private static final byte TAG_NAMES = 1;
private static final byte TAG_SERIAL_NUM = 2;
private KeyIdentifier id = null;
private GeneralNames names = null;
private SerialNumber serialNum = null;
// Encode only the extension value
private void encodeThis() throws IOException {
if (id == null && names == null && serialNum == null) {
this.extensionValue = null;
return;
}
DerOutputStream seq = new DerOutputStream();
DerOutputStream tmp = new DerOutputStream();
if (id != null) {
DerOutputStream tmp1 = new DerOutputStream();
id.encode(tmp1);
tmp.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT,
false, TAG_ID), tmp1);
}
try {
if (names != null) {
DerOutputStream tmp1 = new DerOutputStream();
names.encode(tmp1);
tmp.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT,
true, TAG_NAMES), tmp1);
}
} catch (Exception e) {
throw new IOException(e.toString());
}
if (serialNum != null) {
DerOutputStream tmp1 = new DerOutputStream();
serialNum.encode(tmp1);
tmp.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT,
false, TAG_SERIAL_NUM), tmp1);
}
seq.write(DerValue.tag_Sequence, tmp);
this.extensionValue = seq.toByteArray();
}
/**
* The default constructor for this extension. Null parameters make
* the element optional (not present).
*
* @param id the KeyIdentifier associated with this extension.
* @param names the GeneralNames associated with this extension
* @param serialNum the CertificateSerialNumber associated with
* this extension.
* @exception IOException on error.
*/
public AuthorityKeyIdentifierExtension(KeyIdentifier kid, GeneralNames name,
SerialNumber sn)
throws IOException {
this.id = kid;
this.names = name;
this.serialNum = sn;
this.extensionId = PKIXExtensions.AuthorityKey_Id;
this.critical = false;
encodeThis();
}
/**
* Create the extension from the passed DER encoded value of the same.
*
* @param critical true if the extension is to be treated as critical.
* @param value an array of DER encoded bytes of the actual value.
* @exception ClassCastException if value is not an array of bytes
* @exception IOException on error.
*/
public AuthorityKeyIdentifierExtension(Boolean critical, Object value)
throws IOException {
this.extensionId = PKIXExtensions.AuthorityKey_Id;
this.critical = critical.booleanValue();
this.extensionValue = (byte[]) value;
DerValue val = new DerValue(this.extensionValue);
if (val.tag != DerValue.tag_Sequence) {
throw new IOException("Invalid encoding for " +
"AuthorityKeyIdentifierExtension.");
}
// Note that all the fields in AuthorityKeyIdentifier are defined as
// being OPTIONAL, i.e., there could be an empty SEQUENCE, resulting
// in val.data being null.
while ((val.data != null) && (val.data.available() != 0)) {
DerValue opt = val.data.getDerValue();
// NB. this is always encoded with the IMPLICIT tag
// The checks only make sense if we assume implicit tagging,
// with explicit tagging the form is always constructed.
if (opt.isContextSpecific(TAG_ID) && !opt.isConstructed()) {
if (id != null)
throw new IOException("Duplicate KeyIdentifier in " +
"AuthorityKeyIdentifier.");
opt.resetTag(DerValue.tag_OctetString);
id = new KeyIdentifier(opt);
} else if (opt.isContextSpecific(TAG_NAMES) &&
opt.isConstructed()) {
if (names != null)
throw new IOException("Duplicate GeneralNames in " +
"AuthorityKeyIdentifier.");
opt.resetTag(DerValue.tag_Sequence);
names = new GeneralNames(opt);
} else if (opt.isContextSpecific(TAG_SERIAL_NUM) &&
!opt.isConstructed()) {
if (serialNum != null)
throw new IOException("Duplicate SerialNumber in " +
"AuthorityKeyIdentifier.");
opt.resetTag(DerValue.tag_Integer);
serialNum = new SerialNumber(opt);
} else
throw new IOException("Invalid encoding of " +
"AuthorityKeyIdentifierExtension.");
}
}
/**
* Return the object as a string.
*/
public String toString() {
String s = super.toString() + "AuthorityKeyIdentifier [\n";
if (id != null) {
s += id.toString(); // id already has a newline
}
if (names != null) {
s += names.toString() + "\n";
}
if (serialNum != null) {
s += serialNum.toString() + "\n";
}
return (s + "]\n");
}
/**
* Write the extension to the OutputStream.
*
* @param out the OutputStream to write the extension to.
* @exception IOException on error.
*/
public void encode(OutputStream out) throws IOException {
DerOutputStream tmp = new DerOutputStream();
if (this.extensionValue == null) {
extensionId = PKIXExtensions.AuthorityKey_Id;
critical = false;
encodeThis();
}
super.encode(tmp);
out.write(tmp.toByteArray());
}
/**
* Set the attribute value.
*/
public void set(String name, Object obj) throws IOException {
if (name.equalsIgnoreCase(KEY_ID)) {
if (!(obj instanceof KeyIdentifier)) {
throw new IOException("Attribute value should be of " +
"type KeyIdentifier.");
}
id = (KeyIdentifier)obj;
} else if (name.equalsIgnoreCase(AUTH_NAME)) {
if (!(obj instanceof GeneralNames)) {
throw new IOException("Attribute value should be of " +
"type GeneralNames.");
}
names = (GeneralNames)obj;
} else if (name.equalsIgnoreCase(SERIAL_NUMBER)) {
if (!(obj instanceof SerialNumber)) {
throw new IOException("Attribute value should be of " +
"type SerialNumber.");
}
serialNum = (SerialNumber)obj;
} else {
throw new IOException("Attribute name not recognized by " +
"CertAttrSet:AuthorityKeyIdentifier.");
}
encodeThis();
}
/**
* Get the attribute value.
*/
public Object get(String name) throws IOException {
if (name.equalsIgnoreCase(KEY_ID)) {
return (id);
} else if (name.equalsIgnoreCase(AUTH_NAME)) {
return (names);
} else if (name.equalsIgnoreCase(SERIAL_NUMBER)) {
return (serialNum);
} else {
throw new IOException("Attribute name not recognized by " +
"CertAttrSet:AuthorityKeyIdentifier.");
}
}
/**
* Delete the attribute value.
*/
public void delete(String name) throws IOException {
if (name.equalsIgnoreCase(KEY_ID)) {
id = null;
} else if (name.equalsIgnoreCase(AUTH_NAME)) {
names = null;
} else if (name.equalsIgnoreCase(SERIAL_NUMBER)) {
serialNum = null;
} else {
throw new IOException("Attribute name not recognized by " +
"CertAttrSet:AuthorityKeyIdentifier.");
}
encodeThis();
}
/**
* Return an enumeration of names of attributes existing within this
* attribute.
*/
public Enumeration<String> getElements() {
AttributeNameEnumeration elements = new AttributeNameEnumeration();
elements.addElement(KEY_ID);
elements.addElement(AUTH_NAME);
elements.addElement(SERIAL_NUMBER);
return (elements.elements());
}
/**
* Return the name of this attribute.
*/
public String getName() {
return (NAME);
}
/**
* Return the encoded key identifier, or null if not specified.
*/
public byte[] getEncodedKeyIdentifier() throws IOException {
if (id != null) {
DerOutputStream derOut = new DerOutputStream();
id.encode(derOut);
return derOut.toByteArray();
}
return null;
}
}

View File

@@ -0,0 +1,274 @@
/*
* Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Enumeration;
import sun.security.util.*;
/**
* This class represents the Basic Constraints Extension.
*
* <p>The basic constraints extension identifies whether the subject of the
* certificate is a CA and how deep a certification path may exist
* through that CA.
*
* <pre>
* The ASN.1 syntax for this extension is:
* BasicConstraints ::= SEQUENCE {
* cA BOOLEAN DEFAULT FALSE,
* pathLenConstraint INTEGER (0..MAX) OPTIONAL
* }
* </pre>
* @author Amit Kapoor
* @author Hemma Prafullchandra
* @see CertAttrSet
* @see Extension
*/
public class BasicConstraintsExtension extends Extension
implements CertAttrSet<String> {
/**
* Identifier for this attribute, to be used with the
* get, set, delete methods of Certificate, x509 type.
*/
public static final String IDENT = "x509.info.extensions.BasicConstraints";
/**
* Attribute names.
*/
public static final String NAME = "BasicConstraints";
public static final String IS_CA = "is_ca";
public static final String PATH_LEN = "path_len";
// Private data members
private boolean ca = false;
private int pathLen = -1;
// Encode this extension value
private void encodeThis() throws IOException {
DerOutputStream out = new DerOutputStream();
DerOutputStream tmp = new DerOutputStream();
if (ca) {
tmp.putBoolean(ca);
// Only encode pathLen when ca == true
if (pathLen >= 0) {
tmp.putInteger(pathLen);
}
}
out.write(DerValue.tag_Sequence, tmp);
this.extensionValue = out.toByteArray();
}
/**
* Default constructor for this object. The extension is marked
* critical if the ca flag is true, false otherwise.
*
* @param ca true, if the subject of the Certificate is a CA.
* @param len specifies the depth of the certification path.
*/
public BasicConstraintsExtension(boolean ca, int len) throws IOException {
this(Boolean.valueOf(ca), ca, len);
}
/**
* Constructor for this object with specified criticality.
*
* @param critical true, if the extension should be marked critical
* @param ca true, if the subject of the Certificate is a CA.
* @param len specifies the depth of the certification path.
*/
public BasicConstraintsExtension(Boolean critical, boolean ca, int len)
throws IOException {
this.ca = ca;
this.pathLen = len;
this.extensionId = PKIXExtensions.BasicConstraints_Id;
this.critical = critical.booleanValue();
encodeThis();
}
/**
* Create the extension from the passed DER encoded value of the same.
*
* @param critical flag indicating if extension is critical or not
* @param value an array containing the DER encoded bytes of the extension.
* @exception ClassCastException if value is not an array of bytes
* @exception IOException on error.
*/
public BasicConstraintsExtension(Boolean critical, Object value)
throws IOException
{
this.extensionId = PKIXExtensions.BasicConstraints_Id;
this.critical = critical.booleanValue();
this.extensionValue = (byte[]) value;
DerValue val = new DerValue(this.extensionValue);
if (val.tag != DerValue.tag_Sequence) {
throw new IOException("Invalid encoding of BasicConstraints");
}
if (val.data == null || val.data.available() == 0) {
// non-CA cert ("cA" field is FALSE by default), return -1
return;
}
DerValue opt = val.data.getDerValue();
if (opt.tag != DerValue.tag_Boolean) {
// non-CA cert ("cA" field is FALSE by default), return -1
return;
}
this.ca = opt.getBoolean();
if (val.data.available() == 0) {
// From PKIX profile:
// Where pathLenConstraint does not appear, there is no
// limit to the allowed length of the certification path.
this.pathLen = Integer.MAX_VALUE;
return;
}
opt = val.data.getDerValue();
if (opt.tag != DerValue.tag_Integer) {
throw new IOException("Invalid encoding of BasicConstraints");
}
this.pathLen = opt.getInteger();
/*
* Activate this check once again after PKIX profiling
* is a standard and this check no longer imposes an
* interoperability barrier.
* if (ca) {
* if (!this.critical) {
* throw new IOException("Criticality cannot be false for CA.");
* }
* }
*/
}
/**
* Return user readable form of extension.
*/
public String toString() {
String s = super.toString() + "BasicConstraints:[\n";
s += ((ca) ? (" CA:true") : (" CA:false")) + "\n";
if (pathLen >= 0) {
s += " PathLen:" + pathLen + "\n";
} else {
s += " PathLen: undefined\n";
}
return (s + "]\n");
}
/**
* Encode this extension value to the output stream.
*
* @param out the DerOutputStream to encode the extension to.
*/
public void encode(OutputStream out) throws IOException {
DerOutputStream tmp = new DerOutputStream();
if (extensionValue == null) {
this.extensionId = PKIXExtensions.BasicConstraints_Id;
if (ca) {
critical = true;
} else {
critical = false;
}
encodeThis();
}
super.encode(tmp);
out.write(tmp.toByteArray());
}
/**
* Set the attribute value.
*/
public void set(String name, Object obj) throws IOException {
if (name.equalsIgnoreCase(IS_CA)) {
if (!(obj instanceof Boolean)) {
throw new IOException("Attribute value should be of type Boolean.");
}
ca = ((Boolean)obj).booleanValue();
} else if (name.equalsIgnoreCase(PATH_LEN)) {
if (!(obj instanceof Integer)) {
throw new IOException("Attribute value should be of type Integer.");
}
pathLen = ((Integer)obj).intValue();
} else {
throw new IOException("Attribute name not recognized by " +
"CertAttrSet:BasicConstraints.");
}
encodeThis();
}
/**
* Get the attribute value.
*/
public Object get(String name) throws IOException {
if (name.equalsIgnoreCase(IS_CA)) {
return (Boolean.valueOf(ca));
} else if (name.equalsIgnoreCase(PATH_LEN)) {
return (Integer.valueOf(pathLen));
} else {
throw new IOException("Attribute name not recognized by " +
"CertAttrSet:BasicConstraints.");
}
}
/**
* Delete the attribute value.
*/
public void delete(String name) throws IOException {
if (name.equalsIgnoreCase(IS_CA)) {
ca = false;
} else if (name.equalsIgnoreCase(PATH_LEN)) {
pathLen = -1;
} else {
throw new IOException("Attribute name not recognized by " +
"CertAttrSet:BasicConstraints.");
}
encodeThis();
}
/**
* Return an enumeration of names of attributes existing within this
* attribute.
*/
public Enumeration<String> getElements() {
AttributeNameEnumeration elements = new AttributeNameEnumeration();
elements.addElement(IS_CA);
elements.addElement(PATH_LEN);
return (elements.elements());
}
/**
* Return the name of this attribute.
*/
public String getName() {
return (NAME);
}
}

View File

@@ -0,0 +1,302 @@
/*
* Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.io.OutputStream;
import java.util.*;
import java.util.Collections;
import sun.security.util.DerOutputStream;
import sun.security.util.DerValue;
import sun.security.util.ObjectIdentifier;
/**
* Represent the CRL Distribution Points Extension (OID = 2.5.29.31).
* <p>
* The CRL distribution points extension identifies how CRL information
* is obtained. The extension SHOULD be non-critical, but the PKIX profile
* recommends support for this extension by CAs and applications.
* <p>
* For PKIX, if the cRLDistributionPoints extension contains a
* DistributionPointName of type URI, the following semantics MUST be
* assumed: the URI is a pointer to the current CRL for the associated
* reasons and will be issued by the associated cRLIssuer. The
* expected values for the URI conform to the following rules. The
* name MUST be a non-relative URL, and MUST follow the URL syntax and
* encoding rules specified in [RFC 1738]. The name must include both
* a scheme (e.g., "http" or "ftp") and a scheme-specific-part. The
* scheme- specific-part must include a fully qualified domain name or
* IP address as the host. As specified in [RFC 1738], the scheme
* name is not case-sensitive (e.g., "http" is equivalent to "HTTP").
* The host part is also not case-sensitive, but other components of
* the scheme-specific-part may be case-sensitive. When comparing
* URIs, conforming implementations MUST compare the scheme and host
* without regard to case, but assume the remainder of the
* scheme-specific-part is case sensitive. Processing rules for other
* values are not defined by this specification. If the
* distributionPoint omits reasons, the CRL MUST include revocations
* for all reasons. If the distributionPoint omits cRLIssuer, the CRL
* MUST be issued by the CA that issued the certificate.
* <p>
* The ASN.1 definition for this is:
* <pre>
* id-ce-cRLDistributionPoints OBJECT IDENTIFIER ::= { id-ce 31 }
*
* cRLDistributionPoints ::= {
* CRLDistPointsSyntax }
*
* CRLDistPointsSyntax ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint
* </pre>
* <p>
* @author Anne Anderson
* @author Andreas Sterbenz
* @since 1.4.2
* @see DistributionPoint
* @see Extension
* @see CertAttrSet
*/
public class CRLDistributionPointsExtension extends Extension
implements CertAttrSet<String> {
/**
* Identifier for this attribute, to be used with the
* get, set, delete methods of Certificate, x509 type.
*/
public static final String IDENT =
"x509.info.extensions.CRLDistributionPoints";
/**
* Attribute name.
*/
public static final String NAME = "CRLDistributionPoints";
public static final String POINTS = "points";
/**
* The List of DistributionPoint objects.
*/
private List<DistributionPoint> distributionPoints;
private String extensionName;
/**
* Create a CRLDistributionPointsExtension from a List of
* DistributionPoint; the criticality is set to false.
*
* @param distributionPoints the list of distribution points
* @throws IOException on error
*/
public CRLDistributionPointsExtension(
List<DistributionPoint> distributionPoints) throws IOException {
this(false, distributionPoints);
}
/**
* Create a CRLDistributionPointsExtension from a List of
* DistributionPoint.
*
* @param isCritical the criticality setting.
* @param distributionPoints the list of distribution points
* @throws IOException on error
*/
public CRLDistributionPointsExtension(boolean isCritical,
List<DistributionPoint> distributionPoints) throws IOException {
this(PKIXExtensions.CRLDistributionPoints_Id, isCritical,
distributionPoints, NAME);
}
/**
* Creates the extension (also called by the subclass).
*/
protected CRLDistributionPointsExtension(ObjectIdentifier extensionId,
boolean isCritical, List<DistributionPoint> distributionPoints,
String extensionName) throws IOException {
this.extensionId = extensionId;
this.critical = isCritical;
this.distributionPoints = distributionPoints;
encodeThis();
this.extensionName = extensionName;
}
/**
* Create the extension from the passed DER encoded value of the same.
*
* @param critical true if the extension is to be treated as critical.
* @param value Array of DER encoded bytes of the actual value.
* @exception IOException on error.
*/
public CRLDistributionPointsExtension(Boolean critical, Object value)
throws IOException {
this(PKIXExtensions.CRLDistributionPoints_Id, critical, value, NAME);
}
/**
* Creates the extension (also called by the subclass).
*/
protected CRLDistributionPointsExtension(ObjectIdentifier extensionId,
Boolean critical, Object value, String extensionName)
throws IOException {
this.extensionId = extensionId;
this.critical = critical.booleanValue();
if (!(value instanceof byte[])) {
throw new IOException("Illegal argument type");
}
extensionValue = (byte[])value;
DerValue val = new DerValue(extensionValue);
if (val.tag != DerValue.tag_Sequence) {
throw new IOException("Invalid encoding for " + extensionName +
" extension.");
}
distributionPoints = new ArrayList<DistributionPoint>();
while (val.data.available() != 0) {
DerValue seq = val.data.getDerValue();
DistributionPoint point = new DistributionPoint(seq);
distributionPoints.add(point);
}
this.extensionName = extensionName;
}
/**
* Return the name of this attribute.
*/
public String getName() {
return extensionName;
}
/**
* Write the extension to the DerOutputStream.
*
* @param out the DerOutputStream to write the extension to.
* @exception IOException on encoding errors.
*/
public void encode(OutputStream out) throws IOException {
encode(out, PKIXExtensions.CRLDistributionPoints_Id, false);
}
/**
* Write the extension to the DerOutputStream.
* (Also called by the subclass)
*/
protected void encode(OutputStream out, ObjectIdentifier extensionId,
boolean isCritical) throws IOException {
DerOutputStream tmp = new DerOutputStream();
if (this.extensionValue == null) {
this.extensionId = extensionId;
this.critical = isCritical;
encodeThis();
}
super.encode(tmp);
out.write(tmp.toByteArray());
}
/**
* Set the attribute value.
*/
@SuppressWarnings("unchecked") // Checked with instanceof
public void set(String name, Object obj) throws IOException {
if (name.equalsIgnoreCase(POINTS)) {
if (!(obj instanceof List)) {
throw new IOException("Attribute value should be of type List.");
}
distributionPoints = (List<DistributionPoint>)obj;
} else {
throw new IOException("Attribute name [" + name +
"] not recognized by " +
"CertAttrSet:" + extensionName + ".");
}
encodeThis();
}
/**
* Get the attribute value.
*/
public List<DistributionPoint> get(String name) throws IOException {
if (name.equalsIgnoreCase(POINTS)) {
return distributionPoints;
} else {
throw new IOException("Attribute name [" + name +
"] not recognized by " +
"CertAttrSet:" + extensionName + ".");
}
}
/**
* Delete the attribute value.
*/
public void delete(String name) throws IOException {
if (name.equalsIgnoreCase(POINTS)) {
distributionPoints =
Collections.<DistributionPoint>emptyList();
} else {
throw new IOException("Attribute name [" + name +
"] not recognized by " +
"CertAttrSet:" + extensionName + '.');
}
encodeThis();
}
/**
* Return an enumeration of names of attributes existing within this
* attribute.
*/
public Enumeration<String> getElements() {
AttributeNameEnumeration elements = new AttributeNameEnumeration();
elements.addElement(POINTS);
return elements.elements();
}
// Encode this extension value
private void encodeThis() throws IOException {
if (distributionPoints.isEmpty()) {
this.extensionValue = null;
} else {
DerOutputStream pnts = new DerOutputStream();
for (DistributionPoint point : distributionPoints) {
point.encode(pnts);
}
DerOutputStream seq = new DerOutputStream();
seq.write(DerValue.tag_Sequence, pnts);
this.extensionValue = seq.toByteArray();
}
}
/**
* Return the extension as user readable string.
*/
public String toString() {
return super.toString() + extensionName + " [\n "
+ distributionPoints + "]\n";
}
}

View File

@@ -0,0 +1,299 @@
/*
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.security.cert.CRLException;
import java.security.cert.CertificateException;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Map;
import java.util.TreeMap;
import sun.security.util.*;
/**
* This class defines the CRL Extensions.
* It is used for both CRL Extensions and CRL Entry Extensions,
* which are defined are follows:
* <pre>
* TBSCertList ::= SEQUENCE {
* version Version OPTIONAL, -- if present, must be v2
* signature AlgorithmIdentifier,
* issuer Name,
* thisUpdate Time,
* nextUpdate Time OPTIONAL,
* revokedCertificates SEQUENCE OF SEQUENCE {
* userCertificate CertificateSerialNumber,
* revocationDate Time,
* crlEntryExtensions Extensions OPTIONAL -- if present, must be v2
* } OPTIONAL,
* crlExtensions [0] EXPLICIT Extensions OPTIONAL -- if present, must be v2
* }
* </pre>
*
* @author Hemma Prafullchandra
*/
public class CRLExtensions {
private Map<String,Extension> map = Collections.synchronizedMap(
new TreeMap<String,Extension>());
private boolean unsupportedCritExt = false;
/**
* Default constructor.
*/
public CRLExtensions() { }
/**
* Create the object, decoding the values from the passed DER stream.
*
* @param in the DerInputStream to read the Extension from, i.e. the
* sequence of extensions.
* @exception CRLException on decoding errors.
*/
public CRLExtensions(DerInputStream in) throws CRLException {
init(in);
}
// helper routine
private void init(DerInputStream derStrm) throws CRLException {
try {
DerInputStream str = derStrm;
byte nextByte = (byte)derStrm.peekByte();
// check for context specific byte 0; skip it
if (((nextByte & 0x0c0) == 0x080) &&
((nextByte & 0x01f) == 0x000)) {
DerValue val = str.getDerValue();
str = val.data;
}
DerValue[] exts = str.getSequence(5);
for (int i = 0; i < exts.length; i++) {
Extension ext = new Extension(exts[i]);
parseExtension(ext);
}
} catch (IOException e) {
throw new CRLException("Parsing error: " + e.toString());
}
}
private static final Class[] PARAMS = {Boolean.class, Object.class};
// Parse the encoded extension
private void parseExtension(Extension ext) throws CRLException {
try {
Class<?> extClass = OIDMap.getClass(ext.getExtensionId());
if (extClass == null) { // Unsupported extension
if (ext.isCritical())
unsupportedCritExt = true;
if (map.put(ext.getExtensionId().toString(), ext) != null)
throw new CRLException("Duplicate extensions not allowed");
return;
}
Constructor<?> cons = extClass.getConstructor(PARAMS);
Object[] passed = new Object[] {Boolean.valueOf(ext.isCritical()),
ext.getExtensionValue()};
CertAttrSet<?> crlExt = (CertAttrSet<?>)cons.newInstance(passed);
if (map.put(crlExt.getName(), (Extension)crlExt) != null) {
throw new CRLException("Duplicate extensions not allowed");
}
} catch (InvocationTargetException invk) {
throw new CRLException(invk.getTargetException().getMessage());
} catch (Exception e) {
throw new CRLException(e.toString());
}
}
/**
* Encode the extensions in DER form to the stream.
*
* @param out the DerOutputStream to marshal the contents to.
* @param isExplicit the tag indicating whether this is an entry
* extension (false) or a CRL extension (true).
* @exception CRLException on encoding errors.
*/
public void encode(OutputStream out, boolean isExplicit)
throws CRLException {
try {
DerOutputStream extOut = new DerOutputStream();
Collection<Extension> allExts = map.values();
Object[] objs = allExts.toArray();
for (int i = 0; i < objs.length; i++) {
if (objs[i] instanceof CertAttrSet)
((CertAttrSet)objs[i]).encode(extOut);
else if (objs[i] instanceof Extension)
((Extension)objs[i]).encode(extOut);
else
throw new CRLException("Illegal extension object");
}
DerOutputStream seq = new DerOutputStream();
seq.write(DerValue.tag_Sequence, extOut);
DerOutputStream tmp = new DerOutputStream();
if (isExplicit)
tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT,
true, (byte)0), seq);
else
tmp = seq;
out.write(tmp.toByteArray());
} catch (IOException e) {
throw new CRLException("Encoding error: " + e.toString());
} catch (CertificateException e) {
throw new CRLException("Encoding error: " + e.toString());
}
}
/**
* Get the extension with this alias.
*
* @param alias the identifier string for the extension to retrieve.
*/
public Extension get(String alias) {
X509AttributeName attr = new X509AttributeName(alias);
String name;
String id = attr.getPrefix();
if (id.equalsIgnoreCase(X509CertImpl.NAME)) { // fully qualified
int index = alias.lastIndexOf(".");
name = alias.substring(index + 1);
} else
name = alias;
return map.get(name);
}
/**
* Set the extension value with this alias.
*
* @param alias the identifier string for the extension to set.
* @param obj the Object to set the extension identified by the
* alias.
*/
public void set(String alias, Object obj) {
map.put(alias, (Extension)obj);
}
/**
* Delete the extension value with this alias.
*
* @param alias the identifier string for the extension to delete.
*/
public void delete(String alias) {
map.remove(alias);
}
/**
* Return an enumeration of the extensions.
* @return an enumeration of the extensions in this CRL.
*/
public Enumeration<Extension> getElements() {
return Collections.enumeration(map.values());
}
/**
* Return a collection view of the extensions.
* @return a collection view of the extensions in this CRL.
*/
public Collection<Extension> getAllExtensions() {
return map.values();
}
/**
* Return true if a critical extension is found that is
* not supported, otherwise return false.
*/
public boolean hasUnsupportedCriticalExtension() {
return unsupportedCritExt;
}
/**
* Compares this CRLExtensions for equality with the specified
* object. If the {@code other} object is an
* {@code instanceof} {@code CRLExtensions}, then
* all the entries are compared with the entries from this.
*
* @param other the object to test for equality with this CRLExtensions.
* @return true iff all the entries match that of the Other,
* false otherwise.
*/
public boolean equals(Object other) {
if (this == other)
return true;
if (!(other instanceof CRLExtensions))
return false;
Collection<Extension> otherC =
((CRLExtensions)other).getAllExtensions();
Object[] objs = otherC.toArray();
int len = objs.length;
if (len != map.size())
return false;
Extension otherExt, thisExt;
String key = null;
for (int i = 0; i < len; i++) {
if (objs[i] instanceof CertAttrSet)
key = ((CertAttrSet)objs[i]).getName();
otherExt = (Extension)objs[i];
if (key == null)
key = otherExt.getExtensionId().toString();
thisExt = map.get(key);
if (thisExt == null)
return false;
if (! thisExt.equals(otherExt))
return false;
}
return true;
}
/**
* Returns a hashcode value for this CRLExtensions.
*
* @return the hashcode value.
*/
public int hashCode() {
return map.hashCode();
}
/**
* Returns a string representation of this {@code CRLExtensions} object
* in the form of a set of entries, enclosed in braces and separated
* by the ASCII characters "{@code ,&nbsp;}" (comma and space).
* <p>Overrides to {@code toString} method of {@code Object}.
*
* @return a string representation of this CRLExtensions.
*/
public String toString() {
return map.toString();
}
}

View File

@@ -0,0 +1,235 @@
/*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.io.OutputStream;
import java.math.BigInteger;
import java.util.Enumeration;
import sun.security.util.*;
/**
* Represent the CRL Number Extension.
*
* <p>This extension, if present, conveys a monotonically increasing
* sequence number for each CRL issued by a given CA through a specific
* CA X.500 Directory entry or CRL distribution point. This extension
* allows users to easily determine when a particular CRL supersedes
* another CRL.
*
* @author Hemma Prafullchandra
* @see Extension
* @see CertAttrSet
*/
public class CRLNumberExtension extends Extension
implements CertAttrSet<String> {
/**
* Attribute name.
*/
public static final String NAME = "CRLNumber";
public static final String NUMBER = "value";
private static final String LABEL = "CRL Number";
private BigInteger crlNumber = null;
private String extensionName;
private String extensionLabel;
// Encode this extension value
private void encodeThis() throws IOException {
if (crlNumber == null) {
this.extensionValue = null;
return;
}
DerOutputStream os = new DerOutputStream();
os.putInteger(this.crlNumber);
this.extensionValue = os.toByteArray();
}
/**
* Create a CRLNumberExtension with the integer value .
* The criticality is set to false.
*
* @param crlNum the value to be set for the extension.
*/
public CRLNumberExtension(int crlNum) throws IOException {
this(PKIXExtensions.CRLNumber_Id, false, BigInteger.valueOf(crlNum),
NAME, LABEL);
}
/**
* Create a CRLNumberExtension with the BigInteger value .
* The criticality is set to false.
*
* @param crlNum the value to be set for the extension.
*/
public CRLNumberExtension(BigInteger crlNum) throws IOException {
this(PKIXExtensions.CRLNumber_Id, false, crlNum, NAME, LABEL);
}
/**
* Creates the extension (also called by the subclass).
*/
protected CRLNumberExtension(ObjectIdentifier extensionId,
boolean isCritical, BigInteger crlNum, String extensionName,
String extensionLabel) throws IOException {
this.extensionId = extensionId;
this.critical = isCritical;
this.crlNumber = crlNum;
this.extensionName = extensionName;
this.extensionLabel = extensionLabel;
encodeThis();
}
/**
* Create the extension from the passed DER encoded value of the same.
*
* @param critical true if the extension is to be treated as critical.
* @param value an array of DER encoded bytes of the actual value.
* @exception ClassCastException if value is not an array of bytes
* @exception IOException on error.
*/
public CRLNumberExtension(Boolean critical, Object value)
throws IOException {
this(PKIXExtensions.CRLNumber_Id, critical, value, NAME, LABEL);
}
/**
* Creates the extension (also called by the subclass).
*/
protected CRLNumberExtension(ObjectIdentifier extensionId,
Boolean critical, Object value, String extensionName,
String extensionLabel) throws IOException {
this.extensionId = extensionId;
this.critical = critical.booleanValue();
this.extensionValue = (byte[]) value;
DerValue val = new DerValue(this.extensionValue);
this.crlNumber = val.getBigInteger();
this.extensionName = extensionName;
this.extensionLabel = extensionLabel;
}
/**
* Set the attribute value.
*/
public void set(String name, Object obj) throws IOException {
if (name.equalsIgnoreCase(NUMBER)) {
if (!(obj instanceof BigInteger)) {
throw new IOException("Attribute must be of type BigInteger.");
}
crlNumber = (BigInteger)obj;
} else {
throw new IOException("Attribute name not recognized by"
+ " CertAttrSet:" + extensionName + ".");
}
encodeThis();
}
/**
* Get the attribute value.
*/
public BigInteger get(String name) throws IOException {
if (name.equalsIgnoreCase(NUMBER)) {
return crlNumber;
} else {
throw new IOException("Attribute name not recognized by" +
" CertAttrSet:" + extensionName + '.');
}
}
/**
* Delete the attribute value.
*/
public void delete(String name) throws IOException {
if (name.equalsIgnoreCase(NUMBER)) {
crlNumber = null;
} else {
throw new IOException("Attribute name not recognized by"
+ " CertAttrSet:" + extensionName + ".");
}
encodeThis();
}
/**
* Returns a printable representation of the CRLNumberExtension.
*/
public String toString() {
String s = super.toString() + extensionLabel + ": " +
((crlNumber == null) ? "" : Debug.toHexString(crlNumber))
+ "\n";
return (s);
}
/**
* Write the extension to the DerOutputStream.
*
* @param out the DerOutputStream to write the extension to.
* @exception IOException on encoding errors.
*/
public void encode(OutputStream out) throws IOException {
DerOutputStream tmp = new DerOutputStream();
encode(out, PKIXExtensions.CRLNumber_Id, true);
}
/**
* Write the extension to the DerOutputStream.
* (Also called by the subclass)
*/
protected void encode(OutputStream out, ObjectIdentifier extensionId,
boolean isCritical) throws IOException {
DerOutputStream tmp = new DerOutputStream();
if (this.extensionValue == null) {
this.extensionId = extensionId;
this.critical = isCritical;
encodeThis();
}
super.encode(tmp);
out.write(tmp.toByteArray());
}
/**
* Return an enumeration of names of attributes existing within this
* attribute.
*/
public Enumeration<String> getElements() {
AttributeNameEnumeration elements = new AttributeNameEnumeration();
elements.addElement(NUMBER);
return (elements.elements());
}
/**
* Return the name of this attribute.
*/
public String getName() {
return (extensionName);
}
}

View File

@@ -0,0 +1,202 @@
/*
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.io.OutputStream;
import java.security.cert.CRLReason;
import java.util.Enumeration;
import sun.security.util.*;
/**
* The reasonCode is a non-critical CRL entry extension that identifies
* the reason for the certificate revocation.
* @author Hemma Prafullchandra
* @see java.security.cert.CRLReason
* @see Extension
* @see CertAttrSet
*/
public class CRLReasonCodeExtension extends Extension
implements CertAttrSet<String> {
/**
* Attribute name
*/
public static final String NAME = "CRLReasonCode";
public static final String REASON = "reason";
private static CRLReason[] values = CRLReason.values();
private int reasonCode = 0;
private void encodeThis() throws IOException {
if (reasonCode == 0) {
this.extensionValue = null;
return;
}
DerOutputStream dos = new DerOutputStream();
dos.putEnumerated(reasonCode);
this.extensionValue = dos.toByteArray();
}
/**
* Create a CRLReasonCodeExtension with the passed in reason.
* Criticality automatically set to false.
*
* @param reason the enumerated value for the reason code.
*/
public CRLReasonCodeExtension(int reason) throws IOException {
this(false, reason);
}
/**
* Create a CRLReasonCodeExtension with the passed in reason.
*
* @param critical true if the extension is to be treated as critical.
* @param reason the enumerated value for the reason code.
*/
public CRLReasonCodeExtension(boolean critical, int reason)
throws IOException {
this.extensionId = PKIXExtensions.ReasonCode_Id;
this.critical = critical;
this.reasonCode = reason;
encodeThis();
}
/**
* Create the extension from the passed DER encoded value of the same.
*
* @param critical true if the extension is to be treated as critical.
* @param value an array of DER encoded bytes of the actual value.
* @exception ClassCastException if value is not an array of bytes
* @exception IOException on error.
*/
public CRLReasonCodeExtension(Boolean critical, Object value)
throws IOException {
this.extensionId = PKIXExtensions.ReasonCode_Id;
this.critical = critical.booleanValue();
this.extensionValue = (byte[]) value;
DerValue val = new DerValue(this.extensionValue);
this.reasonCode = val.getEnumerated();
}
/**
* Set the attribute value.
*/
public void set(String name, Object obj) throws IOException {
if (!(obj instanceof Integer)) {
throw new IOException("Attribute must be of type Integer.");
}
if (name.equalsIgnoreCase(REASON)) {
reasonCode = ((Integer)obj).intValue();
} else {
throw new IOException
("Name not supported by CRLReasonCodeExtension");
}
encodeThis();
}
/**
* Get the attribute value.
*/
public Integer get(String name) throws IOException {
if (name.equalsIgnoreCase(REASON)) {
return new Integer(reasonCode);
} else {
throw new IOException
("Name not supported by CRLReasonCodeExtension");
}
}
/**
* Delete the attribute value.
*/
public void delete(String name) throws IOException {
if (name.equalsIgnoreCase(REASON)) {
reasonCode = 0;
} else {
throw new IOException
("Name not supported by CRLReasonCodeExtension");
}
encodeThis();
}
/**
* Returns a printable representation of the Reason code.
*/
public String toString() {
return super.toString() + " Reason Code: " + getReasonCode();
}
/**
* Write the extension to the DerOutputStream.
*
* @param out the DerOutputStream to write the extension to.
* @exception IOException on encoding errors.
*/
public void encode(OutputStream out) throws IOException {
DerOutputStream tmp = new DerOutputStream();
if (this.extensionValue == null) {
this.extensionId = PKIXExtensions.ReasonCode_Id;
this.critical = false;
encodeThis();
}
super.encode(tmp);
out.write(tmp.toByteArray());
}
/**
* Return an enumeration of names of attributes existing within this
* attribute.
*/
public Enumeration<String> getElements() {
AttributeNameEnumeration elements = new AttributeNameEnumeration();
elements.addElement(REASON);
return elements.elements();
}
/**
* Return the name of this attribute.
*/
public String getName() {
return NAME;
}
/**
* Return the reason as a CRLReason enum.
*/
public CRLReason getReasonCode() {
// if out-of-range, return UNSPECIFIED
if (reasonCode > 0 && reasonCode < values.length) {
return values[reasonCode];
} else {
return CRLReason.UNSPECIFIED;
}
}
}

View File

@@ -0,0 +1,117 @@
/*
* Copyright (c) 1997, 2003, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.io.OutputStream;
import java.security.cert.CertificateException;
import java.util.Enumeration;
/**
* This interface defines the methods required of a certificate attribute.
* Examples of X.509 certificate attributes are Validity, Issuer_Name, and
* Subject Name. A CertAttrSet may comprise one attribute or many
* attributes.
* <p>
* A CertAttrSet itself can also be comprised of other sub-sets.
* In the case of X.509 V3 certificates, for example, the "extensions"
* attribute has subattributes, such as those for KeyUsage and
* AuthorityKeyIdentifier.
*
* @author Amit Kapoor
* @author Hemma Prafullchandra
* @see CertificateException
*/
public interface CertAttrSet<T> {
/**
* Returns a short string describing this certificate attribute.
*
* @return value of this certificate attribute in
* printable form.
*/
String toString();
/**
* Encodes the attribute to the output stream in a format
* that can be parsed by the <code>decode</code> method.
*
* @param out the OutputStream to encode the attribute to.
*
* @exception CertificateException on encoding or validity errors.
* @exception IOException on other errors.
*/
void encode(OutputStream out)
throws CertificateException, IOException;
/**
* Sets an attribute value within this CertAttrSet.
*
* @param name the name of the attribute (e.g. "x509.info.key")
* @param obj the attribute object.
*
* @exception CertificateException on attribute handling errors.
* @exception IOException on other errors.
*/
void set(String name, Object obj)
throws CertificateException, IOException;
/**
* Gets an attribute value for this CertAttrSet.
*
* @param name the name of the attribute to return.
*
* @exception CertificateException on attribute handling errors.
* @exception IOException on other errors.
*/
Object get(String name)
throws CertificateException, IOException;
/**
* Deletes an attribute value from this CertAttrSet.
*
* @param name the name of the attribute to delete.
*
* @exception CertificateException on attribute handling errors.
* @exception IOException on other errors.
*/
void delete(String name)
throws CertificateException, IOException;
/**
* Returns an enumeration of the names of the attributes existing within
* this attribute.
*
* @return an enumeration of the attribute names.
*/
Enumeration<T> getElements();
/**
* Returns the name (identifier) of this CertAttrSet.
*
* @return the name of this CertAttrSet.
*/
String getName();
}

View File

@@ -0,0 +1,173 @@
/*
* Copyright (c) 1996, 2004, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
/**
* CertException indicates one of a variety of certificate problems.
*
* @deprecated use one of Exceptions defined in the java.security.cert
* package.
*
* @see java.security.Certificate
*
*
* @author David Brownell
*/
@Deprecated
public class CertException extends SecurityException {
private static final long serialVersionUID = 6930793039696446142L;
// Zero is reserved.
/** Indicates that the signature in the certificate is not valid. */
public static final int verf_INVALID_SIG = 1;
/** Indicates that the certificate was revoked, and so is invalid. */
public static final int verf_INVALID_REVOKED = 2;
/** Indicates that the certificate is not yet valid. */
public static final int verf_INVALID_NOTBEFORE = 3;
/** Indicates that the certificate has expired and so is not valid. */
public static final int verf_INVALID_EXPIRED = 4;
/** Indicates that a certificate authority in the certification
* chain is not trusted. */
public static final int verf_CA_UNTRUSTED = 5;
/** Indicates that the certification chain is too long. */
public static final int verf_CHAIN_LENGTH = 6;
/** Indicates an error parsing the ASN.1/DER encoding of the certificate. */
public static final int verf_PARSE_ERROR = 7;
/** Indicates an error constructing a certificate or certificate chain. */
public static final int err_CONSTRUCTION = 8;
/** Indicates a problem with the public key */
public static final int err_INVALID_PUBLIC_KEY = 9;
/** Indicates a problem with the certificate version */
public static final int err_INVALID_VERSION = 10;
/** Indicates a problem with the certificate format */
public static final int err_INVALID_FORMAT = 11;
/** Indicates a problem with the certificate encoding */
public static final int err_ENCODING = 12;
// Private data members
private int verfCode;
private String moreData;
/**
* Constructs a certificate exception using an error code
* (<code>verf_*</code>) and a string describing the context
* of the error.
*/
public CertException(int code, String moredata)
{
verfCode = code;
moreData = moredata;
}
/**
* Constructs a certificate exception using just an error code,
* without a string describing the context.
*/
public CertException(int code)
{
verfCode = code;
}
/**
* Returns the error code with which the exception was created.
*/
public int getVerfCode() { return verfCode; }
/**
* Returns a string describing the context in which the exception
* was reported.
*/
public String getMoreData() { return moreData; }
/**
* Return a string corresponding to the error code used to create
* this exception.
*/
public String getVerfDescription()
{
switch (verfCode) {
case verf_INVALID_SIG:
return "The signature in the certificate is not valid.";
case verf_INVALID_REVOKED:
return "The certificate has been revoked.";
case verf_INVALID_NOTBEFORE:
return "The certificate is not yet valid.";
case verf_INVALID_EXPIRED:
return "The certificate has expired.";
case verf_CA_UNTRUSTED:
return "The Authority which issued the certificate is not trusted.";
case verf_CHAIN_LENGTH:
return "The certificate path to a trusted authority is too long.";
case verf_PARSE_ERROR:
return "The certificate could not be parsed.";
case err_CONSTRUCTION:
return "There was an error when constructing the certificate.";
case err_INVALID_PUBLIC_KEY:
return "The public key was not in the correct format.";
case err_INVALID_VERSION:
return "The certificate has an invalid version number.";
case err_INVALID_FORMAT:
return "The certificate has an invalid format.";
case err_ENCODING:
return "Problem encountered while encoding the data.";
default:
return "Unknown code: " + verfCode;
}
}
/**
* Returns a string describing the certificate exception.
*/
public String toString()
{
return "[Certificate Exception: " + getMessage() + "]";
}
/**
* Returns a string describing the certificate exception.
*/
public String getMessage()
{
return getVerfDescription()
+ ( (moreData != null)
? ( "\n (" + moreData + ")" ) : "" );
}
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright (c) 1996, 2004, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
/**
* CertException indicates one of a variety of certificate problems.
* @deprecated use one of the Exceptions defined in the
* java.security.cert package.
*
* @author David Brownell
*/
@Deprecated
class CertParseError extends CertException
{
private static final long serialVersionUID = -4559645519017017804L;
CertParseError (String where)
{
super (CertException.verf_PARSE_ERROR, where);
}
}

View File

@@ -0,0 +1,170 @@
/*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import sun.security.util.*;
/**
* This class defines the AlgorithmId for the Certificate.
*
* @author Amit Kapoor
* @author Hemma Prafullchandra
*/
public class CertificateAlgorithmId implements CertAttrSet<String> {
private AlgorithmId algId;
/**
* Identifier for this attribute, to be used with the
* get, set, delete methods of Certificate, x509 type.
*/
public static final String IDENT = "x509.info.algorithmID";
/**
* Sub attributes name for this CertAttrSet.
*/
public static final String NAME = "algorithmID";
/**
* Identifier to be used with get, set, and delete methods. When
* using this identifier the associated object being passed in or
* returned is an instance of AlgorithmId.
* @see sun.security.x509.AlgorithmId
*/
public static final String ALGORITHM = "algorithm";
/**
* Default constructor for the certificate attribute.
*
* @param algId the Algorithm identifier
*/
public CertificateAlgorithmId(AlgorithmId algId) {
this.algId = algId;
}
/**
* Create the object, decoding the values from the passed DER stream.
*
* @param in the DerInputStream to read the serial number from.
* @exception IOException on decoding errors.
*/
public CertificateAlgorithmId(DerInputStream in) throws IOException {
DerValue val = in.getDerValue();
algId = AlgorithmId.parse(val);
}
/**
* Create the object, decoding the values from the passed stream.
*
* @param in the InputStream to read the serial number from.
* @exception IOException on decoding errors.
*/
public CertificateAlgorithmId(InputStream in) throws IOException {
DerValue val = new DerValue(in);
algId = AlgorithmId.parse(val);
}
/**
* Return the algorithm identifier as user readable string.
*/
public String toString() {
if (algId == null) return "";
return (algId.toString() +
", OID = " + (algId.getOID()).toString() + "\n");
}
/**
* Encode the algorithm identifier in DER form to the stream.
*
* @param out the DerOutputStream to marshal the contents to.
* @exception IOException on errors.
*/
public void encode(OutputStream out) throws IOException {
DerOutputStream tmp = new DerOutputStream();
algId.encode(tmp);
out.write(tmp.toByteArray());
}
/**
* Set the attribute value.
*/
public void set(String name, Object obj) throws IOException {
if (!(obj instanceof AlgorithmId)) {
throw new IOException("Attribute must be of type AlgorithmId.");
}
if (name.equalsIgnoreCase(ALGORITHM)) {
algId = (AlgorithmId)obj;
} else {
throw new IOException("Attribute name not recognized by " +
"CertAttrSet:CertificateAlgorithmId.");
}
}
/**
* Get the attribute value.
*/
public AlgorithmId get(String name) throws IOException {
if (name.equalsIgnoreCase(ALGORITHM)) {
return (algId);
} else {
throw new IOException("Attribute name not recognized by " +
"CertAttrSet:CertificateAlgorithmId.");
}
}
/**
* Delete the attribute value.
*/
public void delete(String name) throws IOException {
if (name.equalsIgnoreCase(ALGORITHM)) {
algId = null;
} else {
throw new IOException("Attribute name not recognized by " +
"CertAttrSet:CertificateAlgorithmId.");
}
}
/**
* Return an enumeration of names of attributes existing within this
* attribute.
*/
public Enumeration<String> getElements() {
AttributeNameEnumeration elements = new AttributeNameEnumeration();
elements.addElement(ALGORITHM);
return (elements.elements());
}
/**
* Return the name of this attribute.
*/
public String getName() {
return (NAME);
}
}

View File

@@ -0,0 +1,382 @@
/*
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.security.cert.CertificateException;
import java.util.*;
import sun.misc.HexDumpEncoder;
import sun.security.util.*;
/**
* This class defines the Extensions attribute for the Certificate.
*
* @author Amit Kapoor
* @author Hemma Prafullchandra
* @see CertAttrSet
*/
public class CertificateExtensions implements CertAttrSet<Extension> {
/**
* Identifier for this attribute, to be used with the
* get, set, delete methods of Certificate, x509 type.
*/
public static final String IDENT = "x509.info.extensions";
/**
* name
*/
public static final String NAME = "extensions";
private static final Debug debug = Debug.getInstance("x509");
private Map<String,Extension> map = Collections.synchronizedMap(
new TreeMap<String,Extension>());
private boolean unsupportedCritExt = false;
private Map<String,Extension> unparseableExtensions;
/**
* Default constructor.
*/
public CertificateExtensions() { }
/**
* Create the object, decoding the values from the passed DER stream.
*
* @param in the DerInputStream to read the Extension from.
* @exception IOException on decoding errors.
*/
public CertificateExtensions(DerInputStream in) throws IOException {
init(in);
}
// helper routine
private void init(DerInputStream in) throws IOException {
DerValue[] exts = in.getSequence(5);
for (int i = 0; i < exts.length; i++) {
Extension ext = new Extension(exts[i]);
parseExtension(ext);
}
}
private static Class[] PARAMS = {Boolean.class, Object.class};
// Parse the encoded extension
private void parseExtension(Extension ext) throws IOException {
try {
Class<?> extClass = OIDMap.getClass(ext.getExtensionId());
if (extClass == null) { // Unsupported extension
if (ext.isCritical()) {
unsupportedCritExt = true;
}
if (map.put(ext.getExtensionId().toString(), ext) == null) {
return;
} else {
throw new IOException("Duplicate extensions not allowed");
}
}
Constructor<?> cons = extClass.getConstructor(PARAMS);
Object[] passed = new Object[] {Boolean.valueOf(ext.isCritical()),
ext.getExtensionValue()};
CertAttrSet<?> certExt = (CertAttrSet<?>)
cons.newInstance(passed);
if (map.put(certExt.getName(), (Extension)certExt) != null) {
throw new IOException("Duplicate extensions not allowed");
}
} catch (InvocationTargetException invk) {
Throwable e = invk.getTargetException();
if (ext.isCritical() == false) {
// ignore errors parsing non-critical extensions
if (unparseableExtensions == null) {
unparseableExtensions = new TreeMap<String,Extension>();
}
unparseableExtensions.put(ext.getExtensionId().toString(),
new UnparseableExtension(ext, e));
if (debug != null) {
debug.println("Debug info only." +
" Error parsing extension: " + ext);
e.printStackTrace();
HexDumpEncoder h = new HexDumpEncoder();
System.err.println(h.encodeBuffer(ext.getExtensionValue()));
}
return;
}
if (e instanceof IOException) {
throw (IOException)e;
} else {
throw new IOException(e);
}
} catch (IOException e) {
throw e;
} catch (Exception e) {
throw new IOException(e);
}
}
/**
* Encode the extensions in DER form to the stream, setting
* the context specific tag as needed in the X.509 v3 certificate.
*
* @param out the DerOutputStream to marshal the contents to.
* @exception CertificateException on encoding errors.
* @exception IOException on errors.
*/
public void encode(OutputStream out)
throws CertificateException, IOException {
encode(out, false);
}
/**
* Encode the extensions in DER form to the stream.
*
* @param out the DerOutputStream to marshal the contents to.
* @param isCertReq if true then no context specific tag is added.
* @exception CertificateException on encoding errors.
* @exception IOException on errors.
*/
public void encode(OutputStream out, boolean isCertReq)
throws CertificateException, IOException {
DerOutputStream extOut = new DerOutputStream();
Collection<Extension> allExts = map.values();
Object[] objs = allExts.toArray();
for (int i = 0; i < objs.length; i++) {
if (objs[i] instanceof CertAttrSet)
((CertAttrSet)objs[i]).encode(extOut);
else if (objs[i] instanceof Extension)
((Extension)objs[i]).encode(extOut);
else
throw new CertificateException("Illegal extension object");
}
DerOutputStream seq = new DerOutputStream();
seq.write(DerValue.tag_Sequence, extOut);
DerOutputStream tmp;
if (!isCertReq) { // certificate
tmp = new DerOutputStream();
tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)3),
seq);
} else
tmp = seq; // pkcs#10 certificateRequest
out.write(tmp.toByteArray());
}
/**
* Set the attribute value.
* @param name the extension name used in the cache.
* @param obj the object to set.
* @exception IOException if the object could not be cached.
*/
public void set(String name, Object obj) throws IOException {
if (obj instanceof Extension) {
map.put(name, (Extension)obj);
} else {
throw new IOException("Unknown extension type.");
}
}
/**
* Get the attribute value.
* @param name the extension name used in the lookup.
* @exception IOException if named extension is not found.
*/
public Extension get(String name) throws IOException {
Extension obj = map.get(name);
if (obj == null) {
throw new IOException("No extension found with name " + name);
}
return (obj);
}
// Similar to get(String), but throw no exception, might return null.
// Used in X509CertImpl::getExtension(OID).
Extension getExtension(String name) {
return map.get(name);
}
/**
* Delete the attribute value.
* @param name the extension name used in the lookup.
* @exception IOException if named extension is not found.
*/
public void delete(String name) throws IOException {
Object obj = map.get(name);
if (obj == null) {
throw new IOException("No extension found with name " + name);
}
map.remove(name);
}
public String getNameByOid(ObjectIdentifier oid) throws IOException {
for (String name: map.keySet()) {
if (map.get(name).getExtensionId().equals((Object)oid)) {
return name;
}
}
return null;
}
/**
* Return an enumeration of names of attributes existing within this
* attribute.
*/
public Enumeration<Extension> getElements() {
return Collections.enumeration(map.values());
}
/**
* Return a collection view of the extensions.
* @return a collection view of the extensions in this Certificate.
*/
public Collection<Extension> getAllExtensions() {
return map.values();
}
public Map<String,Extension> getUnparseableExtensions() {
if (unparseableExtensions == null) {
return Collections.emptyMap();
} else {
return unparseableExtensions;
}
}
/**
* Return the name of this attribute.
*/
public String getName() {
return NAME;
}
/**
* Return true if a critical extension is found that is
* not supported, otherwise return false.
*/
public boolean hasUnsupportedCriticalExtension() {
return unsupportedCritExt;
}
/**
* Compares this CertificateExtensions for equality with the specified
* object. If the {@code other} object is an
* {@code instanceof} {@code CertificateExtensions}, then
* all the entries are compared with the entries from this.
*
* @param other the object to test for equality with this
* CertificateExtensions.
* @return true iff all the entries match that of the Other,
* false otherwise.
*/
public boolean equals(Object other) {
if (this == other)
return true;
if (!(other instanceof CertificateExtensions))
return false;
Collection<Extension> otherC =
((CertificateExtensions)other).getAllExtensions();
Object[] objs = otherC.toArray();
int len = objs.length;
if (len != map.size())
return false;
Extension otherExt, thisExt;
String key = null;
for (int i = 0; i < len; i++) {
if (objs[i] instanceof CertAttrSet)
key = ((CertAttrSet)objs[i]).getName();
otherExt = (Extension)objs[i];
if (key == null)
key = otherExt.getExtensionId().toString();
thisExt = map.get(key);
if (thisExt == null)
return false;
if (! thisExt.equals(otherExt))
return false;
}
return this.getUnparseableExtensions().equals(
((CertificateExtensions)other).getUnparseableExtensions());
}
/**
* Returns a hashcode value for this CertificateExtensions.
*
* @return the hashcode value.
*/
public int hashCode() {
return map.hashCode() + getUnparseableExtensions().hashCode();
}
/**
* Returns a string representation of this {@code CertificateExtensions}
* object in the form of a set of entries, enclosed in braces and separated
* by the ASCII characters "{@code ,&nbsp;}" (comma and space).
* <p>Overrides to {@code toString} method of {@code Object}.
*
* @return a string representation of this CertificateExtensions.
*/
public String toString() {
return map.toString();
}
}
class UnparseableExtension extends Extension {
private String name;
private Throwable why;
public UnparseableExtension(Extension ext, Throwable why) {
super(ext);
name = "";
try {
Class<?> extClass = OIDMap.getClass(ext.getExtensionId());
if (extClass != null) {
Field field = extClass.getDeclaredField("NAME");
name = (String)(field.get(null)) + " ";
}
} catch (Exception e) {
// If we cannot find the name, just ignore it
}
this.why = why;
}
@Override public String toString() {
return super.toString() +
"Unparseable " + name + "extension due to\n" + why + "\n\n" +
new sun.misc.HexDumpEncoder().encodeBuffer(getExtensionValue());
}
}

View File

@@ -0,0 +1,209 @@
/*
* Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Enumeration;
import sun.security.util.DerValue;
import sun.security.util.DerOutputStream;
/**
* Represents the CRL Certificate Issuer Extension (OID = 2.5.29.29).
* <p>
* The CRL certificate issuer extension identifies the certificate issuer
* associated with an entry in an indirect CRL, i.e. a CRL that has the
* indirectCRL indicator set in its issuing distribution point extension. If
* this extension is not present on the first entry in an indirect CRL, the
* certificate issuer defaults to the CRL issuer. On subsequent entries
* in an indirect CRL, if this extension is not present, the certificate
* issuer for the entry is the same as that for the preceding entry.
* <p>
* If used by conforming CRL issuers, this extension is always
* critical. If an implementation ignored this extension it could not
* correctly attribute CRL entries to certificates. PKIX (RFC 5280)
* RECOMMENDS that implementations recognize this extension.
* <p>
* The ASN.1 definition for this is:
* <pre>
* id-ce-certificateIssuer OBJECT IDENTIFIER ::= { id-ce 29 }
*
* certificateIssuer ::= GeneralNames
* </pre>
*
* @author Anne Anderson
* @author Sean Mullan
* @since 1.5
* @see Extension
* @see CertAttrSet
*/
public class CertificateIssuerExtension extends Extension
implements CertAttrSet<String> {
/**
* Attribute names.
*/
public static final String NAME = "CertificateIssuer";
public static final String ISSUER = "issuer";
private GeneralNames names;
/**
* Encode this extension
*/
private void encodeThis() throws IOException {
if (names == null || names.isEmpty()) {
this.extensionValue = null;
return;
}
DerOutputStream os = new DerOutputStream();
names.encode(os);
this.extensionValue = os.toByteArray();
}
/**
* Create a CertificateIssuerExtension containing the specified issuer name.
* Criticality is automatically set to true.
*
* @param issuer the certificate issuer
* @throws IOException on error
*/
public CertificateIssuerExtension(GeneralNames issuer) throws IOException {
this.extensionId = PKIXExtensions.CertificateIssuer_Id;
this.critical = true;
this.names = issuer;
encodeThis();
}
/**
* Create a CertificateIssuerExtension from the specified DER encoded
* value of the same.
*
* @param critical true if the extension is to be treated as critical.
* @param value an array of DER encoded bytes of the actual value
* @throws ClassCastException if value is not an array of bytes
* @throws IOException on error
*/
public CertificateIssuerExtension(Boolean critical, Object value)
throws IOException {
this.extensionId = PKIXExtensions.CertificateIssuer_Id;
this.critical = critical.booleanValue();
this.extensionValue = (byte[]) value;
DerValue val = new DerValue(this.extensionValue);
this.names = new GeneralNames(val);
}
/**
* Set the attribute value.
*
* @throws IOException on error
*/
public void set(String name, Object obj) throws IOException {
if (name.equalsIgnoreCase(ISSUER)) {
if (!(obj instanceof GeneralNames)) {
throw new IOException("Attribute value must be of type " +
"GeneralNames");
}
this.names = (GeneralNames)obj;
} else {
throw new IOException("Attribute name not recognized by " +
"CertAttrSet:CertificateIssuer");
}
encodeThis();
}
/**
* Gets the attribute value.
*
* @throws IOException on error
*/
public GeneralNames get(String name) throws IOException {
if (name.equalsIgnoreCase(ISSUER)) {
return names;
} else {
throw new IOException("Attribute name not recognized by " +
"CertAttrSet:CertificateIssuer");
}
}
/**
* Deletes the attribute value.
*
* @throws IOException on error
*/
public void delete(String name) throws IOException {
if (name.equalsIgnoreCase(ISSUER)) {
names = null;
} else {
throw new IOException("Attribute name not recognized by " +
"CertAttrSet:CertificateIssuer");
}
encodeThis();
}
/**
* Returns a printable representation of the certificate issuer.
*/
public String toString() {
return super.toString() + "Certificate Issuer [\n" +
String.valueOf(names) + "]\n";
}
/**
* Write the extension to the OutputStream.
*
* @param out the OutputStream to write the extension to
* @exception IOException on encoding errors
*/
public void encode(OutputStream out) throws IOException {
DerOutputStream tmp = new DerOutputStream();
if (extensionValue == null) {
extensionId = PKIXExtensions.CertificateIssuer_Id;
critical = true;
encodeThis();
}
super.encode(tmp);
out.write(tmp.toByteArray());
}
/**
* Return an enumeration of names of attributes existing within this
* attribute.
*/
public Enumeration<String> getElements() {
AttributeNameEnumeration elements = new AttributeNameEnumeration();
elements.addElement(ISSUER);
return elements.elements();
}
/**
* Return the name of this attribute.
*/
public String getName() {
return NAME;
}
}

View File

@@ -0,0 +1,180 @@
/*
* Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import javax.security.auth.x500.X500Principal;
import sun.security.util.*;
/**
* This class defines the X500Name attribute for the Certificate.
*
* @author Amit Kapoor
* @author Hemma Prafullchandra
* @see CertAttrSet
*/
public class CertificateIssuerName implements CertAttrSet<String> {
/**
* Identifier for this attribute, to be used with the
* get, set, delete methods of Certificate, x509 type.
*/
public static final String IDENT = "x509.info.issuer";
/**
* Sub attributes name for this CertAttrSet.
*/
public static final String NAME = "issuer";
public static final String DN_NAME = "dname";
// accessor name for cached X500Principal only
// do not allow a set() of this value, do not advertise with getElements()
public static final String DN_PRINCIPAL = "x500principal";
// Private data member
private X500Name dnName;
// cached X500Principal version of the name
private X500Principal dnPrincipal;
/**
* Default constructor for the certificate attribute.
*
* @param name the X500Name
*/
public CertificateIssuerName(X500Name name) {
this.dnName = name;
}
/**
* Create the object, decoding the values from the passed DER stream.
*
* @param in the DerInputStream to read the X500Name from.
* @exception IOException on decoding errors.
*/
public CertificateIssuerName(DerInputStream in) throws IOException {
dnName = new X500Name(in);
}
/**
* Create the object, decoding the values from the passed stream.
*
* @param in the InputStream to read the X500Name from.
* @exception IOException on decoding errors.
*/
public CertificateIssuerName(InputStream in) throws IOException {
DerValue derVal = new DerValue(in);
dnName = new X500Name(derVal);
}
/**
* Return the name as user readable string.
*/
public String toString() {
if (dnName == null) return "";
return(dnName.toString());
}
/**
* Encode the name in DER form to the stream.
*
* @param out the DerOutputStream to marshal the contents to.
* @exception IOException on errors.
*/
public void encode(OutputStream out) throws IOException {
DerOutputStream tmp = new DerOutputStream();
dnName.encode(tmp);
out.write(tmp.toByteArray());
}
/**
* Set the attribute value.
*/
public void set(String name, Object obj) throws IOException {
if (!(obj instanceof X500Name)) {
throw new IOException("Attribute must be of type X500Name.");
}
if (name.equalsIgnoreCase(DN_NAME)) {
this.dnName = (X500Name)obj;
this.dnPrincipal = null;
} else {
throw new IOException("Attribute name not recognized by " +
"CertAttrSet:CertificateIssuerName.");
}
}
/**
* Get the attribute value.
*/
public Object get(String name) throws IOException {
if (name.equalsIgnoreCase(DN_NAME)) {
return(dnName);
} else if (name.equalsIgnoreCase(DN_PRINCIPAL)) {
if ((dnPrincipal == null) && (dnName != null)) {
dnPrincipal = dnName.asX500Principal();
}
return dnPrincipal;
} else {
throw new IOException("Attribute name not recognized by " +
"CertAttrSet:CertificateIssuerName.");
}
}
/**
* Delete the attribute value.
*/
public void delete(String name) throws IOException {
if (name.equalsIgnoreCase(DN_NAME)) {
dnName = null;
dnPrincipal = null;
} else {
throw new IOException("Attribute name not recognized by " +
"CertAttrSet:CertificateIssuerName.");
}
}
/**
* Return an enumeration of names of attributes existing within this
* attribute.
*/
public Enumeration<String> getElements() {
AttributeNameEnumeration elements = new AttributeNameEnumeration();
elements.addElement(DN_NAME);
return (elements.elements());
}
/**
* Return the name of this attribute.
*/
public String getName() {
return(NAME);
}
}

View File

@@ -0,0 +1,252 @@
/*
* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.io.OutputStream;
import java.util.*;
import sun.security.util.DerValue;
import sun.security.util.DerOutputStream;
/**
* This class defines the certificate policies extension which specifies the
* policies under which the certificate has been issued
* and the purposes for which the certificate may be used.
* <p>
* Applications with specific policy requirements are expected to have a
* list of those policies which they will accept and to compare the
* policy OIDs in the certificate to that list. If this extension is
* critical, the path validation software MUST be able to interpret this
* extension (including the optional qualifier), or MUST reject the
* certificate.
* <p>
* Optional qualifiers are not supported in this implementation, as they are
* not recommended by RFC2459.
*
* The ASN.1 syntax for this is (IMPLICIT tagging is defined in the
* module definition):
* <pre>
* id-ce-certificatePolicies OBJECT IDENTIFIER ::= { id-ce 32 }
*
* certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation
*
* PolicyInformation ::= SEQUENCE {
* policyIdentifier CertPolicyId,
* policyQualifiers SEQUENCE SIZE (1..MAX) OF
* PolicyQualifierInfo OPTIONAL }
*
* CertPolicyId ::= OBJECT IDENTIFIER
* </pre>
* @author Anne Anderson
* @since 1.4
* @see Extension
* @see CertAttrSet
*/
public class CertificatePoliciesExtension extends Extension
implements CertAttrSet<String> {
/**
* Identifier for this attribute, to be used with the
* get, set, delete methods of Certificate, x509 type.
*/
public static final String IDENT = "x509.info.extensions.CertificatePolicies";
/**
* Attribute names.
*/
public static final String NAME = "CertificatePolicies";
public static final String POLICIES = "policies";
/**
* List of PolicyInformation for this object.
*/
private List<PolicyInformation> certPolicies;
// Encode this extension value.
private void encodeThis() throws IOException {
if (certPolicies == null || certPolicies.isEmpty()) {
this.extensionValue = null;
} else {
DerOutputStream os = new DerOutputStream();
DerOutputStream tmp = new DerOutputStream();
for (PolicyInformation info : certPolicies) {
info.encode(tmp);
}
os.write(DerValue.tag_Sequence, tmp);
this.extensionValue = os.toByteArray();
}
}
/**
* Create a CertificatePoliciesExtension object from
* a List of PolicyInformation; the criticality is set to false.
*
* @param certPolicies the List of PolicyInformation.
*/
public CertificatePoliciesExtension(List<PolicyInformation> certPolicies)
throws IOException {
this(Boolean.FALSE, certPolicies);
}
/**
* Create a CertificatePoliciesExtension object from
* a List of PolicyInformation with specified criticality.
*
* @param critical true if the extension is to be treated as critical.
* @param certPolicies the List of PolicyInformation.
*/
public CertificatePoliciesExtension(Boolean critical,
List<PolicyInformation> certPolicies) throws IOException {
this.certPolicies = certPolicies;
this.extensionId = PKIXExtensions.CertificatePolicies_Id;
this.critical = critical.booleanValue();
encodeThis();
}
/**
* Create the extension from its DER encoded value and criticality.
*
* @param critical true if the extension is to be treated as critical.
* @param value an array of DER encoded bytes of the actual value.
* @exception ClassCastException if value is not an array of bytes
* @exception IOException on error.
*/
public CertificatePoliciesExtension(Boolean critical, Object value)
throws IOException {
this.extensionId = PKIXExtensions.CertificatePolicies_Id;
this.critical = critical.booleanValue();
this.extensionValue = (byte[]) value;
DerValue val = new DerValue(this.extensionValue);
if (val.tag != DerValue.tag_Sequence) {
throw new IOException("Invalid encoding for " +
"CertificatePoliciesExtension.");
}
certPolicies = new ArrayList<PolicyInformation>();
while (val.data.available() != 0) {
DerValue seq = val.data.getDerValue();
PolicyInformation policy = new PolicyInformation(seq);
certPolicies.add(policy);
}
}
/**
* Return the extension as user readable string.
*/
public String toString() {
if (certPolicies == null) {
return "";
}
StringBuilder sb = new StringBuilder(super.toString());
sb.append("CertificatePolicies [\n");
for (PolicyInformation info : certPolicies) {
sb.append(info.toString());
}
sb.append("]\n");
return sb.toString();
}
/**
* Write the extension to the DerOutputStream.
*
* @param out the DerOutputStream to write the extension to.
* @exception IOException on encoding errors.
*/
public void encode(OutputStream out) throws IOException {
DerOutputStream tmp = new DerOutputStream();
if (extensionValue == null) {
extensionId = PKIXExtensions.CertificatePolicies_Id;
critical = false;
encodeThis();
}
super.encode(tmp);
out.write(tmp.toByteArray());
}
/**
* Set the attribute value.
*/
@SuppressWarnings("unchecked") // Checked with an instanceof check
public void set(String name, Object obj) throws IOException {
if (name.equalsIgnoreCase(POLICIES)) {
if (!(obj instanceof List)) {
throw new IOException("Attribute value should be of type List.");
}
certPolicies = (List<PolicyInformation>)obj;
} else {
throw new IOException("Attribute name [" + name +
"] not recognized by " +
"CertAttrSet:CertificatePoliciesExtension.");
}
encodeThis();
}
/**
* Get the attribute value.
*/
public List<PolicyInformation> get(String name) throws IOException {
if (name.equalsIgnoreCase(POLICIES)) {
//XXXX May want to consider cloning this
return certPolicies;
} else {
throw new IOException("Attribute name [" + name +
"] not recognized by " +
"CertAttrSet:CertificatePoliciesExtension.");
}
}
/**
* Delete the attribute value.
*/
public void delete(String name) throws IOException {
if (name.equalsIgnoreCase(POLICIES)) {
certPolicies = null;
} else {
throw new IOException("Attribute name [" + name +
"] not recognized by " +
"CertAttrSet:CertificatePoliciesExtension.");
}
encodeThis();
}
/**
* Return an enumeration of names of attributes existing within this
* attribute.
*/
public Enumeration<String> getElements() {
AttributeNameEnumeration elements = new AttributeNameEnumeration();
elements.addElement(POLICIES);
return (elements.elements());
}
/**
* Return the name of this attribute.
*/
public String getName() {
return (NAME);
}
}

View File

@@ -0,0 +1,110 @@
/*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import sun.security.util.*;
/**
* Represent the CertificatePolicyId ASN.1 object.
*
* @author Amit Kapoor
* @author Hemma Prafullchandra
*/
public class CertificatePolicyId {
private ObjectIdentifier id;
/**
* Create a CertificatePolicyId with the ObjectIdentifier.
*
* @param id the ObjectIdentifier for the policy id.
*/
public CertificatePolicyId(ObjectIdentifier id) {
this.id = id;
}
/**
* Create the object from its Der encoded value.
*
* @param val the DER encoded value for the same.
*/
public CertificatePolicyId(DerValue val) throws IOException {
this.id = val.getOID();
}
/**
* Return the value of the CertificatePolicyId as an ObjectIdentifier.
*/
public ObjectIdentifier getIdentifier() {
return (id);
}
/**
* Returns a printable representation of the CertificatePolicyId.
*/
public String toString() {
String s = "CertificatePolicyId: ["
+ id.toString()
+ "]\n";
return (s);
}
/**
* Write the CertificatePolicyId to the DerOutputStream.
*
* @param out the DerOutputStream to write the object to.
* @exception IOException on errors.
*/
public void encode(DerOutputStream out) throws IOException {
out.putOID(id);
}
/**
* Compares this CertificatePolicyId with another, for
* equality. Uses ObjectIdentifier.equals() as test for
* equality.
*
* @return true iff the ids are identical.
*/
public boolean equals(Object other) {
if (other instanceof CertificatePolicyId)
return id.equals((Object)
((CertificatePolicyId) other).getIdentifier());
else
return false;
}
/**
* Returns a hash code value for this object.
*
* @return a hash code value
*/
public int hashCode() {
return id.hashCode();
}
}

View File

@@ -0,0 +1,106 @@
/*
* Copyright (c) 1997, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import sun.security.util.*;
/**
* Represent the CertificatePolicyMap ASN.1 object.
*
* @author Amit Kapoor
* @author Hemma Prafullchandra
*/
public class CertificatePolicyMap {
private CertificatePolicyId issuerDomain;
private CertificatePolicyId subjectDomain;
/**
* Create a CertificatePolicyMap with the passed CertificatePolicyId's.
*
* @param issuer the CertificatePolicyId for the issuer CA.
* @param subject the CertificatePolicyId for the subject CA.
*/
public CertificatePolicyMap(CertificatePolicyId issuer,
CertificatePolicyId subject) {
this.issuerDomain = issuer;
this.subjectDomain = subject;
}
/**
* Create the CertificatePolicyMap from the DER encoded value.
*
* @param val the DER encoded value of the same.
*/
public CertificatePolicyMap(DerValue val) throws IOException {
if (val.tag != DerValue.tag_Sequence) {
throw new IOException("Invalid encoding for CertificatePolicyMap");
}
issuerDomain = new CertificatePolicyId(val.data.getDerValue());
subjectDomain = new CertificatePolicyId(val.data.getDerValue());
}
/**
* Return the issuer CA part of the policy map.
*/
public CertificatePolicyId getIssuerIdentifier() {
return (issuerDomain);
}
/**
* Return the subject CA part of the policy map.
*/
public CertificatePolicyId getSubjectIdentifier() {
return (subjectDomain);
}
/**
* Returns a printable representation of the CertificatePolicyId.
*/
public String toString() {
String s = "CertificatePolicyMap: [\n"
+ "IssuerDomain:" + issuerDomain.toString()
+ "SubjectDomain:" + subjectDomain.toString()
+ "]\n";
return (s);
}
/**
* Write the CertificatePolicyMap to the DerOutputStream.
*
* @param out the DerOutputStream to write the object to.
* @exception IOException on errors.
*/
public void encode(DerOutputStream out) throws IOException {
DerOutputStream tmp = new DerOutputStream();
issuerDomain.encode(tmp);
subjectDomain.encode(tmp);
out.write(DerValue.tag_Sequence,tmp);
}
}

View File

@@ -0,0 +1,104 @@
/*
* Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.util.Vector;
import java.util.List;
import java.util.Collections;
import sun.security.util.*;
/**
* This class defines the certificate policy set ASN.1 object.
*
* @author Amit Kapoor
* @author Hemma Prafullchandra
*/
public class CertificatePolicySet {
private final Vector<CertificatePolicyId> ids;
/**
* The default constructor for this class.
*
* @param ids the sequence of CertificatePolicyId's.
*/
public CertificatePolicySet(Vector<CertificatePolicyId> ids) {
this.ids = ids;
}
/**
* Create the object from the DerValue.
*
* @param in the passed DerInputStream.
* @exception IOException on decoding errors.
*/
public CertificatePolicySet(DerInputStream in) throws IOException {
ids = new Vector<CertificatePolicyId>();
DerValue[] seq = in.getSequence(5);
for (int i = 0; i < seq.length; i++) {
CertificatePolicyId id = new CertificatePolicyId(seq[i]);
ids.addElement(id);
}
}
/**
* Return printable form of the object.
*/
public String toString() {
String s = "CertificatePolicySet:[\n"
+ ids.toString()
+ "]\n";
return (s);
}
/**
* Encode the policy set to the output stream.
*
* @param out the DerOutputStream to encode the data to.
*/
public void encode(DerOutputStream out) throws IOException {
DerOutputStream tmp = new DerOutputStream();
for (int i = 0; i < ids.size(); i++) {
ids.elementAt(i).encode(tmp);
}
out.write(DerValue.tag_Sequence,tmp);
}
/**
* Return the sequence of CertificatePolicyIds.
*
* @return A List containing the CertificatePolicyId objects.
*
*/
public List<CertificatePolicyId> getCertPolicyIds() {
return Collections.unmodifiableList(ids);
}
}

View File

@@ -0,0 +1,182 @@
/*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.util.Enumeration;
import sun.security.util.*;
/**
* This class defines the SerialNumber attribute for the Certificate.
*
* @author Amit Kapoor
* @author Hemma Prafullchandra
* @see CertAttrSet
*/
public class CertificateSerialNumber implements CertAttrSet<String> {
/**
* Identifier for this attribute, to be used with the
* get, set, delete methods of Certificate, x509 type.
*/
public static final String IDENT = "x509.info.serialNumber";
/**
* Sub attributes name for this CertAttrSet.
*/
public static final String NAME = "serialNumber";
public static final String NUMBER = "number";
private SerialNumber serial;
/**
* Default constructor for the certificate attribute.
*
* @param serial the serial number for the certificate.
*/
public CertificateSerialNumber(BigInteger num) {
this.serial = new SerialNumber(num);
}
/**
* Default constructor for the certificate attribute.
*
* @param serial the serial number for the certificate.
*/
public CertificateSerialNumber(int num) {
this.serial = new SerialNumber(num);
}
/**
* Create the object, decoding the values from the passed DER stream.
*
* @param in the DerInputStream to read the serial number from.
* @exception IOException on decoding errors.
*/
public CertificateSerialNumber(DerInputStream in) throws IOException {
serial = new SerialNumber(in);
}
/**
* Create the object, decoding the values from the passed stream.
*
* @param in the InputStream to read the serial number from.
* @exception IOException on decoding errors.
*/
public CertificateSerialNumber(InputStream in) throws IOException {
serial = new SerialNumber(in);
}
/**
* Create the object, decoding the values from the passed DerValue.
*
* @param val the DER encoded value.
* @exception IOException on decoding errors.
*/
public CertificateSerialNumber(DerValue val) throws IOException {
serial = new SerialNumber(val);
}
/**
* Return the serial number as user readable string.
*/
public String toString() {
if (serial == null) return "";
return (serial.toString());
}
/**
* Encode the serial number in DER form to the stream.
*
* @param out the DerOutputStream to marshal the contents to.
* @exception IOException on errors.
*/
public void encode(OutputStream out) throws IOException {
DerOutputStream tmp = new DerOutputStream();
serial.encode(tmp);
out.write(tmp.toByteArray());
}
/**
* Set the attribute value.
*/
public void set(String name, Object obj) throws IOException {
if (!(obj instanceof SerialNumber)) {
throw new IOException("Attribute must be of type SerialNumber.");
}
if (name.equalsIgnoreCase(NUMBER)) {
serial = (SerialNumber)obj;
} else {
throw new IOException("Attribute name not recognized by " +
"CertAttrSet:CertificateSerialNumber.");
}
}
/**
* Get the attribute value.
*/
public SerialNumber get(String name) throws IOException {
if (name.equalsIgnoreCase(NUMBER)) {
return (serial);
} else {
throw new IOException("Attribute name not recognized by " +
"CertAttrSet:CertificateSerialNumber.");
}
}
/**
* Delete the attribute value.
*/
public void delete(String name) throws IOException {
if (name.equalsIgnoreCase(NUMBER)) {
serial = null;
} else {
throw new IOException("Attribute name not recognized by " +
"CertAttrSet:CertificateSerialNumber.");
}
}
/**
* Return an enumeration of names of attributes existing within this
* attribute.
*/
public Enumeration<String> getElements() {
AttributeNameEnumeration elements = new AttributeNameEnumeration();
elements.addElement(NUMBER);
return (elements.elements());
}
/**
* Return the name of this attribute.
*/
public String getName() {
return (NAME);
}
}

View File

@@ -0,0 +1,180 @@
/*
* Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import javax.security.auth.x500.X500Principal;
import sun.security.util.*;
/**
* This class defines the X500Name attribute for the Certificate.
*
* @author Amit Kapoor
* @author Hemma Prafullchandra
* @see CertAttrSet
*/
public class CertificateSubjectName implements CertAttrSet<String> {
/**
* Identifier for this attribute, to be used with the
* get, set, delete methods of Certificate, x509 type.
*/
public static final String IDENT = "x509.info.subject";
/**
* Sub attributes name for this CertAttrSet.
*/
public static final String NAME = "subject";
public static final String DN_NAME = "dname";
// accessor name for cached X500Principal only
// do not allow a set() of this value, do not advertise with getElements()
public static final String DN_PRINCIPAL = "x500principal";
// Private data member
private X500Name dnName;
// cached X500Principal version of the name
private X500Principal dnPrincipal;
/**
* Default constructor for the certificate attribute.
*
* @param name the X500Name
*/
public CertificateSubjectName(X500Name name) {
this.dnName = name;
}
/**
* Create the object, decoding the values from the passed DER stream.
*
* @param in the DerInputStream to read the X500Name from.
* @exception IOException on decoding errors.
*/
public CertificateSubjectName(DerInputStream in) throws IOException {
dnName = new X500Name(in);
}
/**
* Create the object, decoding the values from the passed stream.
*
* @param in the InputStream to read the X500Name from.
* @exception IOException on decoding errors.
*/
public CertificateSubjectName(InputStream in) throws IOException {
DerValue derVal = new DerValue(in);
dnName = new X500Name(derVal);
}
/**
* Return the name as user readable string.
*/
public String toString() {
if (dnName == null) return "";
return(dnName.toString());
}
/**
* Encode the name in DER form to the stream.
*
* @param out the DerOutputStream to marshal the contents to.
* @exception IOException on errors.
*/
public void encode(OutputStream out) throws IOException {
DerOutputStream tmp = new DerOutputStream();
dnName.encode(tmp);
out.write(tmp.toByteArray());
}
/**
* Set the attribute value.
*/
public void set(String name, Object obj) throws IOException {
if (!(obj instanceof X500Name)) {
throw new IOException("Attribute must be of type X500Name.");
}
if (name.equalsIgnoreCase(DN_NAME)) {
this.dnName = (X500Name)obj;
this.dnPrincipal = null;
} else {
throw new IOException("Attribute name not recognized by " +
"CertAttrSet:CertificateSubjectName.");
}
}
/**
* Get the attribute value.
*/
public Object get(String name) throws IOException {
if (name.equalsIgnoreCase(DN_NAME)) {
return(dnName);
} else if (name.equalsIgnoreCase(DN_PRINCIPAL)) {
if ((dnPrincipal == null) && (dnName != null)) {
dnPrincipal = dnName.asX500Principal();
}
return dnPrincipal;
} else {
throw new IOException("Attribute name not recognized by " +
"CertAttrSet:CertificateSubjectName.");
}
}
/**
* Delete the attribute value.
*/
public void delete(String name) throws IOException {
if (name.equalsIgnoreCase(DN_NAME)) {
dnName = null;
dnPrincipal = null;
} else {
throw new IOException("Attribute name not recognized by " +
"CertAttrSet:CertificateSubjectName.");
}
}
/**
* Return an enumeration of names of attributes existing within this
* attribute.
*/
public Enumeration<String> getElements() {
AttributeNameEnumeration elements = new AttributeNameEnumeration();
elements.addElement(DN_NAME);
return(elements.elements());
}
/**
* Return the name of this attribute.
*/
public String getName() {
return(NAME);
}
}

View File

@@ -0,0 +1,280 @@
/*
* Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.io.OutputStream;
import java.security.cert.*;
import java.util.Date;
import java.util.Enumeration;
import sun.security.util.*;
/**
* This class defines the interval for which the certificate is valid.
*
* @author Amit Kapoor
* @author Hemma Prafullchandra
* @see CertAttrSet
*/
public class CertificateValidity implements CertAttrSet<String> {
/**
* Identifier for this attribute, to be used with the
* get, set, delete methods of Certificate, x509 type.
*/
public static final String IDENT = "x509.info.validity";
/**
* Sub attributes name for this CertAttrSet.
*/
public static final String NAME = "validity";
public static final String NOT_BEFORE = "notBefore";
public static final String NOT_AFTER = "notAfter";
/**
* YR_2050 date and time set to Jan01 00:00 2050 GMT
*/
static final long YR_2050 = 2524608000000L;
// Private data members
private Date notBefore;
private Date notAfter;
// Returns the first time the certificate is valid.
private Date getNotBefore() {
return (new Date(notBefore.getTime()));
}
// Returns the last time the certificate is valid.
private Date getNotAfter() {
return (new Date(notAfter.getTime()));
}
// Construct the class from the DerValue
private void construct(DerValue derVal) throws IOException {
if (derVal.tag != DerValue.tag_Sequence) {
throw new IOException("Invalid encoded CertificateValidity, " +
"starting sequence tag missing.");
}
// check if UTCTime encoded or GeneralizedTime
if (derVal.data.available() == 0)
throw new IOException("No data encoded for CertificateValidity");
DerInputStream derIn = new DerInputStream(derVal.toByteArray());
DerValue[] seq = derIn.getSequence(2);
if (seq.length != 2)
throw new IOException("Invalid encoding for CertificateValidity");
if (seq[0].tag == DerValue.tag_UtcTime) {
notBefore = derVal.data.getUTCTime();
} else if (seq[0].tag == DerValue.tag_GeneralizedTime) {
notBefore = derVal.data.getGeneralizedTime();
} else {
throw new IOException("Invalid encoding for CertificateValidity");
}
if (seq[1].tag == DerValue.tag_UtcTime) {
notAfter = derVal.data.getUTCTime();
} else if (seq[1].tag == DerValue.tag_GeneralizedTime) {
notAfter = derVal.data.getGeneralizedTime();
} else {
throw new IOException("Invalid encoding for CertificateValidity");
}
}
/**
* Default constructor for the class.
*/
public CertificateValidity() { }
/**
* The default constructor for this class for the specified interval.
*
* @param notBefore the date and time before which the certificate
* is not valid.
* @param notAfter the date and time after which the certificate is
* not valid.
*/
public CertificateValidity(Date notBefore, Date notAfter) {
this.notBefore = notBefore;
this.notAfter = notAfter;
}
/**
* Create the object, decoding the values from the passed DER stream.
*
* @param in the DerInputStream to read the CertificateValidity from.
* @exception IOException on decoding errors.
*/
public CertificateValidity(DerInputStream in) throws IOException {
DerValue derVal = in.getDerValue();
construct(derVal);
}
/**
* Return the validity period as user readable string.
*/
public String toString() {
if (notBefore == null || notAfter == null)
return "";
return ("Validity: [From: " + notBefore.toString() +
",\n To: " + notAfter.toString() + "]");
}
/**
* Encode the CertificateValidity period in DER form to the stream.
*
* @param out the OutputStream to marshal the contents to.
* @exception IOException on errors.
*/
public void encode(OutputStream out) throws IOException {
// in cases where default constructor is used check for
// null values
if (notBefore == null || notAfter == null) {
throw new IOException("CertAttrSet:CertificateValidity:" +
" null values to encode.\n");
}
DerOutputStream pair = new DerOutputStream();
if (notBefore.getTime() < YR_2050) {
pair.putUTCTime(notBefore);
} else
pair.putGeneralizedTime(notBefore);
if (notAfter.getTime() < YR_2050) {
pair.putUTCTime(notAfter);
} else {
pair.putGeneralizedTime(notAfter);
}
DerOutputStream seq = new DerOutputStream();
seq.write(DerValue.tag_Sequence, pair);
out.write(seq.toByteArray());
}
/**
* Set the attribute value.
*/
public void set(String name, Object obj) throws IOException {
if (!(obj instanceof Date)) {
throw new IOException("Attribute must be of type Date.");
}
if (name.equalsIgnoreCase(NOT_BEFORE)) {
notBefore = (Date)obj;
} else if (name.equalsIgnoreCase(NOT_AFTER)) {
notAfter = (Date)obj;
} else {
throw new IOException("Attribute name not recognized by " +
"CertAttrSet: CertificateValidity.");
}
}
/**
* Get the attribute value.
*/
public Date get(String name) throws IOException {
if (name.equalsIgnoreCase(NOT_BEFORE)) {
return (getNotBefore());
} else if (name.equalsIgnoreCase(NOT_AFTER)) {
return (getNotAfter());
} else {
throw new IOException("Attribute name not recognized by " +
"CertAttrSet: CertificateValidity.");
}
}
/**
* Delete the attribute value.
*/
public void delete(String name) throws IOException {
if (name.equalsIgnoreCase(NOT_BEFORE)) {
notBefore = null;
} else if (name.equalsIgnoreCase(NOT_AFTER)) {
notAfter = null;
} else {
throw new IOException("Attribute name not recognized by " +
"CertAttrSet: CertificateValidity.");
}
}
/**
* Return an enumeration of names of attributes existing within this
* attribute.
*/
public Enumeration<String> getElements() {
AttributeNameEnumeration elements = new AttributeNameEnumeration();
elements.addElement(NOT_BEFORE);
elements.addElement(NOT_AFTER);
return (elements.elements());
}
/**
* Return the name of this attribute.
*/
public String getName() {
return (NAME);
}
/**
* Verify that the current time is within the validity period.
*
* @exception CertificateExpiredException if the certificate has expired.
* @exception CertificateNotYetValidException if the certificate is not
* yet valid.
*/
public void valid()
throws CertificateNotYetValidException, CertificateExpiredException {
Date now = new Date();
valid(now);
}
/**
* Verify that the passed time is within the validity period.
* @param now the Date against which to compare the validity
* period.
*
* @exception CertificateExpiredException if the certificate has expired
* with respect to the <code>Date</code> supplied.
* @exception CertificateNotYetValidException if the certificate is not
* yet valid with respect to the <code>Date</code> supplied.
*
*/
public void valid(Date now)
throws CertificateNotYetValidException, CertificateExpiredException {
/*
* we use the internal Dates rather than the passed in Date
* because someone could override the Date methods after()
* and before() to do something entirely different.
*/
if (notBefore.after(now)) {
throw new CertificateNotYetValidException("NotBefore: " +
notBefore.toString());
}
if (notAfter.before(now)) {
throw new CertificateExpiredException("NotAfter: " +
notAfter.toString());
}
}
}

View File

@@ -0,0 +1,239 @@
/*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import sun.security.util.*;
/**
* This class defines the version of the X509 Certificate.
*
* @author Amit Kapoor
* @author Hemma Prafullchandra
* @see CertAttrSet
*/
public class CertificateVersion implements CertAttrSet<String> {
/**
* X509Certificate Version 1
*/
public static final int V1 = 0;
/**
* X509Certificate Version 2
*/
public static final int V2 = 1;
/**
* X509Certificate Version 3
*/
public static final int V3 = 2;
/**
* Identifier for this attribute, to be used with the
* get, set, delete methods of Certificate, x509 type.
*/
public static final String IDENT = "x509.info.version";
/**
* Sub attributes name for this CertAttrSet.
*/
public static final String NAME = "version";
public static final String VERSION = "number";
// Private data members
int version = V1;
// Returns the version number.
private int getVersion() {
return(version);
}
// Construct the class from the passed DerValue
private void construct(DerValue derVal) throws IOException {
if (derVal.isConstructed() && derVal.isContextSpecific()) {
derVal = derVal.data.getDerValue();
version = derVal.getInteger();
if (derVal.data.available() != 0) {
throw new IOException("X.509 version, bad format");
}
}
}
/**
* The default constructor for this class,
* sets the version to 0 (i.e. X.509 version 1).
*/
public CertificateVersion() {
version = V1;
}
/**
* The constructor for this class for the required version.
*
* @param version the version for the certificate.
* @exception IOException if the version is not valid.
*/
public CertificateVersion(int version) throws IOException {
// check that it is a valid version
if (version == V1 || version == V2 || version == V3)
this.version = version;
else {
throw new IOException("X.509 Certificate version " +
version + " not supported.\n");
}
}
/**
* Create the object, decoding the values from the passed DER stream.
*
* @param in the DerInputStream to read the CertificateVersion from.
* @exception IOException on decoding errors.
*/
public CertificateVersion(DerInputStream in) throws IOException {
version = V1;
DerValue derVal = in.getDerValue();
construct(derVal);
}
/**
* Create the object, decoding the values from the passed stream.
*
* @param in the InputStream to read the CertificateVersion from.
* @exception IOException on decoding errors.
*/
public CertificateVersion(InputStream in) throws IOException {
version = V1;
DerValue derVal = new DerValue(in);
construct(derVal);
}
/**
* Create the object, decoding the values from the passed DerValue.
*
* @param val the Der encoded value.
* @exception IOException on decoding errors.
*/
public CertificateVersion(DerValue val) throws IOException {
version = V1;
construct(val);
}
/**
* Return the version number of the certificate.
*/
public String toString() {
return("Version: V" + (version+1));
}
/**
* Encode the CertificateVersion period in DER form to the stream.
*
* @param out the OutputStream to marshal the contents to.
* @exception IOException on errors.
*/
public void encode(OutputStream out) throws IOException {
// Nothing for default
if (version == V1) {
return;
}
DerOutputStream tmp = new DerOutputStream();
tmp.putInteger(version);
DerOutputStream seq = new DerOutputStream();
seq.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0),
tmp);
out.write(seq.toByteArray());
}
/**
* Set the attribute value.
*/
public void set(String name, Object obj) throws IOException {
if (!(obj instanceof Integer)) {
throw new IOException("Attribute must be of type Integer.");
}
if (name.equalsIgnoreCase(VERSION)) {
version = ((Integer)obj).intValue();
} else {
throw new IOException("Attribute name not recognized by " +
"CertAttrSet: CertificateVersion.");
}
}
/**
* Get the attribute value.
*/
public Integer get(String name) throws IOException {
if (name.equalsIgnoreCase(VERSION)) {
return(new Integer(getVersion()));
} else {
throw new IOException("Attribute name not recognized by " +
"CertAttrSet: CertificateVersion.");
}
}
/**
* Delete the attribute value.
*/
public void delete(String name) throws IOException {
if (name.equalsIgnoreCase(VERSION)) {
version = V1;
} else {
throw new IOException("Attribute name not recognized by " +
"CertAttrSet: CertificateVersion.");
}
}
/**
* Return an enumeration of names of attributes existing within this
* attribute.
*/
public Enumeration<String> getElements() {
AttributeNameEnumeration elements = new AttributeNameEnumeration();
elements.addElement(VERSION);
return (elements.elements());
}
/**
* Return the name of this attribute.
*/
public String getName() {
return(NAME);
}
/**
* Compare versions.
*/
public int compare(int vers) {
return(version - vers);
}
}

View File

@@ -0,0 +1,163 @@
/*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.security.PublicKey;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Enumeration;
import sun.security.util.*;
/**
* This class defines the X509Key attribute for the Certificate.
*
* @author Amit Kapoor
* @author Hemma Prafullchandra
* @see CertAttrSet
*/
public class CertificateX509Key implements CertAttrSet<String> {
/**
* Identifier for this attribute, to be used with the
* get, set, delete methods of Certificate, x509 type.
*/
public static final String IDENT = "x509.info.key";
/**
* Sub attributes name for this CertAttrSet.
*/
public static final String NAME = "key";
public static final String KEY = "value";
// Private data member
private PublicKey key;
/**
* Default constructor for the certificate attribute.
*
* @param key the X509Key
*/
public CertificateX509Key(PublicKey key) {
this.key = key;
}
/**
* Create the object, decoding the values from the passed DER stream.
*
* @param in the DerInputStream to read the X509Key from.
* @exception IOException on decoding errors.
*/
public CertificateX509Key(DerInputStream in) throws IOException {
DerValue val = in.getDerValue();
key = X509Key.parse(val);
}
/**
* Create the object, decoding the values from the passed stream.
*
* @param in the InputStream to read the X509Key from.
* @exception IOException on decoding errors.
*/
public CertificateX509Key(InputStream in) throws IOException {
DerValue val = new DerValue(in);
key = X509Key.parse(val);
}
/**
* Return the key as printable string.
*/
public String toString() {
if (key == null) return "";
return(key.toString());
}
/**
* Encode the key in DER form to the stream.
*
* @param out the OutputStream to marshal the contents to.
* @exception IOException on errors.
*/
public void encode(OutputStream out) throws IOException {
DerOutputStream tmp = new DerOutputStream();
tmp.write(key.getEncoded());
out.write(tmp.toByteArray());
}
/**
* Set the attribute value.
*/
public void set(String name, Object obj) throws IOException {
if (name.equalsIgnoreCase(KEY)) {
this.key = (PublicKey)obj;
} else {
throw new IOException("Attribute name not recognized by " +
"CertAttrSet: CertificateX509Key.");
}
}
/**
* Get the attribute value.
*/
public PublicKey get(String name) throws IOException {
if (name.equalsIgnoreCase(KEY)) {
return(key);
} else {
throw new IOException("Attribute name not recognized by " +
"CertAttrSet: CertificateX509Key.");
}
}
/**
* Delete the attribute value.
*/
public void delete(String name) throws IOException {
if (name.equalsIgnoreCase(KEY)) {
key = null;
} else {
throw new IOException("Attribute name not recognized by " +
"CertAttrSet: CertificateX509Key.");
}
}
/**
* Return an enumeration of names of attributes existing within this
* attribute.
*/
public Enumeration<String> getElements() {
AttributeNameEnumeration elements = new AttributeNameEnumeration();
elements.addElement(KEY);
return(elements.elements());
}
/**
* Return the name of this attribute.
*/
public String getName() {
return(NAME);
}
}

View File

@@ -0,0 +1,278 @@
/*
* Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.util.Locale;
import sun.security.util.*;
/**
* This class implements the DNSName as required by the GeneralNames
* ASN.1 object.
* <p>
* [RFC5280] When the subjectAltName extension contains a domain name system
* label, the domain name MUST be stored in the dNSName (an IA5String).
* The name MUST be in the "preferred name syntax", as specified by
* Section 3.5 of [RFC1034] and as modified by Section 2.1 of
* [RFC1123]. Note that while uppercase and lowercase letters are
* allowed in domain names, no significance is attached to the case. In
* addition, while the string " " is a legal domain name, subjectAltName
* extensions with a dNSName of " " MUST NOT be used. Finally, the use
* of the DNS representation for Internet mail addresses
* (subscriber.example.com instead of subscriber@example.com) MUST NOT
* be used; such identities are to be encoded as rfc822Name.
* <p>
* @author Amit Kapoor
* @author Hemma Prafullchandra
*/
public class DNSName implements GeneralNameInterface {
private String name;
private static final String alphaDigits =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
/**
* Create the DNSName object from the passed encoded Der value.
*
* @param derValue the encoded DER DNSName.
* @exception IOException on error.
*/
public DNSName(DerValue derValue) throws IOException {
name = derValue.getIA5String();
}
/**
* Create the DNSName object with the specified name.
*
* @param name the DNSName.
* @param allowWildcard the flag for wildcard checking.
* @throws IOException if the name is not a valid DNSName
*/
public DNSName(String name, boolean allowWildcard) throws IOException {
if (name == null || name.length() == 0)
throw new IOException("DNSName must not be null or empty");
if (name.contains(" "))
throw new IOException("DNSName with blank components is not permitted");
if (name.startsWith(".") || name.endsWith("."))
throw new IOException("DNSName may not begin or end with a .");
/*
* Name will consist of label components separated by "."
* startIndex is the index of the first character of a component
* endIndex is the index of the last character of a component plus 1
*/
for (int endIndex,startIndex = 0; startIndex < name.length(); startIndex = endIndex+1) {
endIndex = name.indexOf('.', startIndex);
if (endIndex < 0) {
endIndex = name.length();
}
if (endIndex - startIndex < 1)
throw new IOException("DNSName with empty components are not permitted");
if (allowWildcard) {
// RFC 1123: DNSName components must begin with a letter or digit
// or RFC 4592: the first component of a DNSName can have only a wildcard
// character * (asterisk), i.e. *.example.com. Asterisks at other components
// will not be allowed as a wildcard.
if (alphaDigits.indexOf(name.charAt(startIndex)) < 0) {
// Checking to make sure the wildcard only appears in the first component,
// and it has to be at least 3-char long with the form of *.[alphaDigit]
if ((name.length() < 3) || (name.indexOf('*', 0) != 0) ||
(name.charAt(startIndex+1) != '.') ||
(alphaDigits.indexOf(name.charAt(startIndex+2)) < 0))
throw new IOException("DNSName components must begin with a letter, digit, "
+ "or the first component can have only a wildcard character *");
}
} else {
// RFC 1123: DNSName components must begin with a letter or digit
if (alphaDigits.indexOf(name.charAt(startIndex)) < 0)
throw new IOException("DNSName components must begin with a letter or digit");
}
//nonStartIndex: index for characters in the component beyond the first one
for (int nonStartIndex=startIndex+1; nonStartIndex < endIndex; nonStartIndex++) {
char x = name.charAt(nonStartIndex);
if ((alphaDigits).indexOf(x) < 0 && x != '-')
throw new IOException("DNSName components must consist of letters, digits, and hyphens");
}
}
this.name = name;
}
/**
* Create the DNSName object with the specified name.
*
* @param name the DNSName.
* @throws IOException if the name is not a valid DNSName
*/
public DNSName(String name) throws IOException {
this(name, false);
}
/**
* Return the type of the GeneralName.
*/
public int getType() {
return (GeneralNameInterface.NAME_DNS);
}
/**
* Return the actual name value of the GeneralName.
*/
public String getName() {
return name;
}
/**
* Encode the DNSName into the DerOutputStream.
*
* @param out the DER stream to encode the DNSName to.
* @exception IOException on encoding errors.
*/
public void encode(DerOutputStream out) throws IOException {
out.putIA5String(name);
}
/**
* Convert the name into user readable string.
*/
public String toString() {
return ("DNSName: " + name);
}
/**
* Compares this name with another, for equality.
*
* @return true iff the names are equivalent
* according to RFC5280.
*/
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!(obj instanceof DNSName))
return false;
DNSName other = (DNSName)obj;
// RFC5280 mandates that these names are
// not case-sensitive
return name.equalsIgnoreCase(other.name);
}
/**
* Returns the hash code value for this object.
*
* @return a hash code value for this object.
*/
public int hashCode() {
return name.toUpperCase(Locale.ENGLISH).hashCode();
}
/**
* Return type of constraint inputName places on this name:<ul>
* <li>NAME_DIFF_TYPE = -1: input name is different type from name (i.e. does not constrain).
* <li>NAME_MATCH = 0: input name matches name.
* <li>NAME_NARROWS = 1: input name narrows name (is lower in the naming subtree)
* <li>NAME_WIDENS = 2: input name widens name (is higher in the naming subtree)
* <li>NAME_SAME_TYPE = 3: input name does not match or narrow name, but is same type.
* </ul>. These results are used in checking NameConstraints during
* certification path verification.
* <p>
* RFC5280: DNS name restrictions are expressed as host.example.com.
* Any DNS name that can be constructed by simply adding zero or more
* labels to the left-hand side of the name satisfies the name constraint.
* For example, www.host.example.com would satisfy the constraint but
* host1.example.com would not.
* <p>
* draft-ietf-pkix-new-part1-00.txt: DNSName restrictions are expressed as foo.bar.com.
* Any DNSName that
* can be constructed by simply adding to the left hand side of the name
* satisfies the name constraint. For example, www.foo.bar.com would
* satisfy the constraint but foo1.bar.com would not.
* <p>
* RFC1034: By convention, domain names can be stored with arbitrary case, but
* domain name comparisons for all present domain functions are done in a
* case-insensitive manner, assuming an ASCII character set, and a high
* order zero bit.
* <p>
* @param inputName to be checked for being constrained
* @returns constraint type above
* @throws UnsupportedOperationException if name is not exact match, but narrowing and widening are
* not supported for this name type.
*/
public int constrains(GeneralNameInterface inputName) throws UnsupportedOperationException {
int constraintType;
if (inputName == null)
constraintType = NAME_DIFF_TYPE;
else if (inputName.getType() != NAME_DNS)
constraintType = NAME_DIFF_TYPE;
else {
String inName =
(((DNSName)inputName).getName()).toLowerCase(Locale.ENGLISH);
String thisName = name.toLowerCase(Locale.ENGLISH);
if (inName.equals(thisName))
constraintType = NAME_MATCH;
else if (thisName.endsWith(inName)) {
int inNdx = thisName.lastIndexOf(inName);
if (thisName.charAt(inNdx-1) == '.' )
constraintType = NAME_WIDENS;
else
constraintType = NAME_SAME_TYPE;
} else if (inName.endsWith(thisName)) {
int ndx = inName.lastIndexOf(thisName);
if (inName.charAt(ndx-1) == '.' )
constraintType = NAME_NARROWS;
else
constraintType = NAME_SAME_TYPE;
} else {
constraintType = NAME_SAME_TYPE;
}
}
return constraintType;
}
/**
* Return subtree depth of this name for purposes of determining
* NameConstraints minimum and maximum bounds and for calculating
* path lengths in name subtrees.
*
* @returns distance of name from root
* @throws UnsupportedOperationException if not supported for this name type
*/
public int subtreeDepth() throws UnsupportedOperationException {
// subtree depth is always at least 1
int sum = 1;
// count dots
for (int i = name.indexOf('.'); i >= 0; i = name.indexOf('.', i + 1)) {
++sum;
}
return sum;
}
}

View File

@@ -0,0 +1,116 @@
/*
* Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.io.OutputStream;
import java.math.BigInteger;
import java.util.Enumeration;
import sun.security.util.*;
/**
* Represents the Delta CRL Indicator Extension.
*
* <p>
* The extension identifies a CRL as being a delta CRL.
* Delta CRLs contain updates to revocation information previously distributed,
* rather than all the information that would appear in a complete CRL.
* The extension contains a CRL number that identifies the CRL, complete for a
* given scope, that was used as the starting point in the generation of
* this delta CRL.
*
* <p>
* The extension is defined in Section 5.2.4 of
* <a href="http://tools.ietf.org/html/rfc5280">Internet X.509 PKI Certific
ate and Certificate Revocation List (CRL) Profile</a>.
*
* <p>
* Its ASN.1 definition is as follows:
* <pre>
* id-ce-deltaCRLIndicator OBJECT IDENTIFIER ::= { id-ce 27 }
*
* BaseCRLNumber ::= CRLNumber
* CRLNumber ::= INTEGER (0..MAX)
* </pre>
*
* @since 1.6
*/
public class DeltaCRLIndicatorExtension extends CRLNumberExtension {
/**
* Attribute name.
*/
public static final String NAME = "DeltaCRLIndicator";
private static final String LABEL = "Base CRL Number";
/**
* Creates a delta CRL indicator extension with the integer value .
* The criticality is set to true.
*
* @param crlNum the value to be set for the extension.
*/
public DeltaCRLIndicatorExtension(int crlNum) throws IOException {
super(PKIXExtensions.DeltaCRLIndicator_Id, true,
BigInteger.valueOf(crlNum), NAME, LABEL);
}
/**
* Creates a delta CRL indictor extension with the BigInteger value .
* The criticality is set to true.
*
* @param crlNum the value to be set for the extension.
*/
public DeltaCRLIndicatorExtension(BigInteger crlNum) throws IOException {
super(PKIXExtensions.DeltaCRLIndicator_Id, true, crlNum, NAME, LABEL);
}
/**
* Creates the extension from the passed DER encoded value of the same.
*
* @param critical true if the extension is to be treated as critical.
* @param value an array of DER encoded bytes of the actual value.
* @exception ClassCastException if value is not an array of bytes
* @exception IOException on decoding error.
*/
public DeltaCRLIndicatorExtension(Boolean critical, Object value)
throws IOException {
super(PKIXExtensions.DeltaCRLIndicator_Id, critical.booleanValue(),
value, NAME, LABEL);
}
/**
* Writes the extension to the DerOutputStream.
*
* @param out the DerOutputStream to write the extension to.
* @exception IOException on encoding errors.
*/
public void encode(OutputStream out) throws IOException {
DerOutputStream tmp = new DerOutputStream();
super.encode(out, PKIXExtensions.DeltaCRLIndicator_Id, true);
}
}

View File

@@ -0,0 +1,404 @@
/*
* Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.util.*;
import sun.security.util.BitArray;
import sun.security.util.DerOutputStream;
import sun.security.util.DerValue;
/**
* Represent the DistributionPoint sequence used in the CRL
* Distribution Points Extension (OID = 2.5.29.31).
* <p>
* The ASN.1 definition for this is:
* <pre>
* DistributionPoint ::= SEQUENCE {
* distributionPoint [0] DistributionPointName OPTIONAL,
* reasons [1] ReasonFlags OPTIONAL,
* cRLIssuer [2] GeneralNames OPTIONAL }
*
* DistributionPointName ::= CHOICE {
* fullName [0] GeneralNames,
* nameRelativeToCRLIssuer [1] RelativeDistinguishedName }
*
* ReasonFlags ::= BIT STRING {
* unused (0),
* keyCompromise (1),
* cACompromise (2),
* affiliationChanged (3),
* superseded (4),
* cessationOfOperation (5),
* certificateHold (6),
* privilegeWithdrawn (7),
* aACompromise (8) }
*
* GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
*
* GeneralName ::= CHOICE {
* otherName [0] INSTANCE OF OTHER-NAME,
* rfc822Name [1] IA5String,
* dNSName [2] IA5String,
* x400Address [3] ORAddress,
* directoryName [4] Name,
* ediPartyName [5] EDIPartyName,
* uniformResourceIdentifier [6] IA5String,
* iPAddress [7] OCTET STRING,
* registeredID [8] OBJECT IDENTIFIER }
*
* RelativeDistinguishedName ::=
* SET OF AttributeTypeAndValue
*
* AttributeTypeAndValue ::= SEQUENCE {
* type AttributeType,
* value AttributeValue }
*
* AttributeType ::= OBJECT IDENTIFIER
*
* AttributeValue ::= ANY DEFINED BY AttributeType
* </pre>
* <p>
* Instances of this class are designed to be immutable. However, since this
* is an internal API we do not use defensive cloning for values for
* performance reasons. It is the responsibility of the consumer to ensure
* that no mutable elements are modified.
*
* @author Anne Anderson
* @author Andreas Sterbenz
* @since 1.4.2
* @see CRLDistributionPointsExtension
*/
public class DistributionPoint {
// reason flag bits
// NOTE that these are NOT quite the same as the CRL reason code extension
public final static int KEY_COMPROMISE = 1;
public final static int CA_COMPROMISE = 2;
public final static int AFFILIATION_CHANGED = 3;
public final static int SUPERSEDED = 4;
public final static int CESSATION_OF_OPERATION = 5;
public final static int CERTIFICATE_HOLD = 6;
public final static int PRIVILEGE_WITHDRAWN = 7;
public final static int AA_COMPROMISE = 8;
private static final String[] REASON_STRINGS = {
null,
"key compromise",
"CA compromise",
"affiliation changed",
"superseded",
"cessation of operation",
"certificate hold",
"privilege withdrawn",
"AA compromise",
};
// context specific tag values
private static final byte TAG_DIST_PT = 0;
private static final byte TAG_REASONS = 1;
private static final byte TAG_ISSUER = 2;
private static final byte TAG_FULL_NAME = 0;
private static final byte TAG_REL_NAME = 1;
// only one of fullName and relativeName can be set
private GeneralNames fullName;
private RDN relativeName;
// reasonFlags or null
private boolean[] reasonFlags;
// crlIssuer or null
private GeneralNames crlIssuer;
// cached hashCode value
private volatile int hashCode;
/**
* Constructor for the class using GeneralNames for DistributionPointName
*
* @param fullName the GeneralNames of the distribution point; may be null
* @param reasons the CRL reasons included in the CRL at this distribution
* point; may be null
* @param issuer the name(s) of the CRL issuer for the CRL at this
* distribution point; may be null
*/
public DistributionPoint(GeneralNames fullName, boolean[] reasonFlags,
GeneralNames crlIssuer) {
if ((fullName == null) && (crlIssuer == null)) {
throw new IllegalArgumentException
("fullName and crlIssuer may not both be null");
}
this.fullName = fullName;
this.reasonFlags = reasonFlags;
this.crlIssuer = crlIssuer;
}
/**
* Constructor for the class using RelativeDistinguishedName for
* DistributionPointName
*
* @param relativeName the RelativeDistinguishedName of the distribution
* point; may not be null
* @param reasons the CRL reasons included in the CRL at this distribution
* point; may be null
* @param issuer the name(s) of the CRL issuer for the CRL at this
* distribution point; may not be null or empty.
*/
public DistributionPoint(RDN relativeName, boolean[] reasonFlags,
GeneralNames crlIssuer) {
if ((relativeName == null) && (crlIssuer == null)) {
throw new IllegalArgumentException
("relativeName and crlIssuer may not both be null");
}
this.relativeName = relativeName;
this.reasonFlags = reasonFlags;
this.crlIssuer = crlIssuer;
}
/**
* Create the object from the passed DER encoded form.
*
* @param val the DER encoded form of the DistributionPoint
* @throws IOException on error
*/
public DistributionPoint(DerValue val) throws IOException {
if (val.tag != DerValue.tag_Sequence) {
throw new IOException("Invalid encoding of DistributionPoint.");
}
// Note that all the fields in DistributionPoint are defined as
// being OPTIONAL, i.e., there could be an empty SEQUENCE, resulting
// in val.data being null.
while ((val.data != null) && (val.data.available() != 0)) {
DerValue opt = val.data.getDerValue();
if (opt.isContextSpecific(TAG_DIST_PT) && opt.isConstructed()) {
if ((fullName != null) || (relativeName != null)) {
throw new IOException("Duplicate DistributionPointName in "
+ "DistributionPoint.");
}
DerValue distPnt = opt.data.getDerValue();
if (distPnt.isContextSpecific(TAG_FULL_NAME)
&& distPnt.isConstructed()) {
distPnt.resetTag(DerValue.tag_Sequence);
fullName = new GeneralNames(distPnt);
} else if (distPnt.isContextSpecific(TAG_REL_NAME)
&& distPnt.isConstructed()) {
distPnt.resetTag(DerValue.tag_Set);
relativeName = new RDN(distPnt);
} else {
throw new IOException("Invalid DistributionPointName in "
+ "DistributionPoint");
}
} else if (opt.isContextSpecific(TAG_REASONS)
&& !opt.isConstructed()) {
if (reasonFlags != null) {
throw new IOException("Duplicate Reasons in " +
"DistributionPoint.");
}
opt.resetTag(DerValue.tag_BitString);
reasonFlags = (opt.getUnalignedBitString()).toBooleanArray();
} else if (opt.isContextSpecific(TAG_ISSUER)
&& opt.isConstructed()) {
if (crlIssuer != null) {
throw new IOException("Duplicate CRLIssuer in " +
"DistributionPoint.");
}
opt.resetTag(DerValue.tag_Sequence);
crlIssuer = new GeneralNames(opt);
} else {
throw new IOException("Invalid encoding of " +
"DistributionPoint.");
}
}
if ((crlIssuer == null) && (fullName == null) && (relativeName == null)) {
throw new IOException("One of fullName, relativeName, "
+ " and crlIssuer has to be set");
}
}
/**
* Return the full distribution point name or null if not set.
*/
public GeneralNames getFullName() {
return fullName;
}
/**
* Return the relative distribution point name or null if not set.
*/
public RDN getRelativeName() {
return relativeName;
}
/**
* Return the reason flags or null if not set.
*/
public boolean[] getReasonFlags() {
return reasonFlags;
}
/**
* Return the CRL issuer name or null if not set.
*/
public GeneralNames getCRLIssuer() {
return crlIssuer;
}
/**
* Write the DistributionPoint value to the DerOutputStream.
*
* @param out the DerOutputStream to write the extension to.
* @exception IOException on error.
*/
public void encode(DerOutputStream out) throws IOException {
DerOutputStream tagged = new DerOutputStream();
// NOTE: only one of pointNames and pointRDN can be set
if ((fullName != null) || (relativeName != null)) {
DerOutputStream distributionPoint = new DerOutputStream();
if (fullName != null) {
DerOutputStream derOut = new DerOutputStream();
fullName.encode(derOut);
distributionPoint.writeImplicit(
DerValue.createTag(DerValue.TAG_CONTEXT, true, TAG_FULL_NAME),
derOut);
} else if (relativeName != null) {
DerOutputStream derOut = new DerOutputStream();
relativeName.encode(derOut);
distributionPoint.writeImplicit(
DerValue.createTag(DerValue.TAG_CONTEXT, true, TAG_REL_NAME),
derOut);
}
tagged.write(
DerValue.createTag(DerValue.TAG_CONTEXT, true, TAG_DIST_PT),
distributionPoint);
}
if (reasonFlags != null) {
DerOutputStream reasons = new DerOutputStream();
BitArray rf = new BitArray(reasonFlags);
reasons.putTruncatedUnalignedBitString(rf);
tagged.writeImplicit(
DerValue.createTag(DerValue.TAG_CONTEXT, false, TAG_REASONS),
reasons);
}
if (crlIssuer != null) {
DerOutputStream issuer = new DerOutputStream();
crlIssuer.encode(issuer);
tagged.writeImplicit(
DerValue.createTag(DerValue.TAG_CONTEXT, true, TAG_ISSUER),
issuer);
}
out.write(DerValue.tag_Sequence, tagged);
}
/**
* Compare an object to this DistributionPoint for equality.
*
* @param obj Object to be compared to this
* @return true if objects match; false otherwise
*/
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof DistributionPoint == false) {
return false;
}
DistributionPoint other = (DistributionPoint)obj;
boolean equal = Objects.equals(this.fullName, other.fullName)
&& Objects.equals(this.relativeName, other.relativeName)
&& Objects.equals(this.crlIssuer, other.crlIssuer)
&& Arrays.equals(this.reasonFlags, other.reasonFlags);
return equal;
}
public int hashCode() {
int hash = hashCode;
if (hash == 0) {
hash = 1;
if (fullName != null) {
hash += fullName.hashCode();
}
if (relativeName != null) {
hash += relativeName.hashCode();
}
if (crlIssuer != null) {
hash += crlIssuer.hashCode();
}
if (reasonFlags != null) {
for (int i = 0; i < reasonFlags.length; i++) {
if (reasonFlags[i]) {
hash += i;
}
}
}
hashCode = hash;
}
return hash;
}
/**
* Return a string representation for reasonFlag bit 'reason'.
*/
private static String reasonToString(int reason) {
if ((reason > 0) && (reason < REASON_STRINGS.length)) {
return REASON_STRINGS[reason];
}
return "Unknown reason " + reason;
}
/**
* Return a printable string of the Distribution Point.
*/
public String toString() {
StringBuilder sb = new StringBuilder();
if (fullName != null) {
sb.append("DistributionPoint:\n " + fullName + "\n");
}
if (relativeName != null) {
sb.append("DistributionPoint:\n " + relativeName + "\n");
}
if (reasonFlags != null) {
sb.append(" ReasonFlags:\n");
for (int i = 0; i < reasonFlags.length; i++) {
if (reasonFlags[i]) {
sb.append(" " + reasonToString(i) + "\n");
}
}
}
if (crlIssuer != null) {
sb.append(" CRLIssuer:" + crlIssuer + "\n");
}
return sb.toString();
}
}

View File

@@ -0,0 +1,242 @@
/*
* Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.util.*;
import sun.security.util.BitArray;
import sun.security.util.DerOutputStream;
import sun.security.util.DerValue;
/**
* Represents the DistributionPointName ASN.1 type.
*
* It is used in the CRL Distribution Points Extension (OID = 2.5.29.31)
* and the Issuing Distribution Point Extension (OID = 2.5.29.28).
* <p>
* Its ASN.1 definition is:
* <pre>
*
* DistributionPointName ::= CHOICE {
* fullName [0] GeneralNames,
* nameRelativeToCRLIssuer [1] RelativeDistinguishedName }
*
* GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
*
* GeneralName ::= CHOICE {
* otherName [0] INSTANCE OF OTHER-NAME,
* rfc822Name [1] IA5String,
* dNSName [2] IA5String,
* x400Address [3] ORAddress,
* directoryName [4] Name,
* ediPartyName [5] EDIPartyName,
* uniformResourceIdentifier [6] IA5String,
* iPAddress [7] OCTET STRING,
* registeredID [8] OBJECT IDENTIFIER }
*
* RelativeDistinguishedName ::= SET OF AttributeTypeAndValue
*
* AttributeTypeAndValue ::= SEQUENCE {
* type AttributeType,
* value AttributeValue }
*
* AttributeType ::= OBJECT IDENTIFIER
*
* AttributeValue ::= ANY DEFINED BY AttributeType
*
* </pre>
* <p>
* Instances of this class are designed to be immutable. However, since this
* is an internal API we do not use defensive cloning for values for
* performance reasons. It is the responsibility of the consumer to ensure
* that no mutable elements are modified.
*
* @see CRLDistributionPointsExtension
* @see IssuingDistributionPointExtension
* @since 1.6
*/
public class DistributionPointName {
// ASN.1 context specific tag values
private static final byte TAG_FULL_NAME = 0;
private static final byte TAG_RELATIVE_NAME = 1;
// Only one of fullName and relativeName can be set
private GeneralNames fullName = null;
private RDN relativeName = null;
// Cached hashCode value
private volatile int hashCode;
/**
* Creates a distribution point name using a full name.
*
* @param fullName the name for the distribution point.
* @exception IllegalArgumentException if <code>fullName</code> is null.
*/
public DistributionPointName(GeneralNames fullName) {
if (fullName == null) {
throw new IllegalArgumentException("fullName must not be null");
}
this.fullName = fullName;
}
/**
* Creates a distribution point name using a relative name.
*
* @param relativeName the name of the distribution point relative to
* the name of the issuer of the CRL.
* @exception IllegalArgumentException if <code>relativeName</code> is null.
*/
public DistributionPointName(RDN relativeName) {
if (relativeName == null) {
throw new IllegalArgumentException("relativeName must not be null");
}
this.relativeName = relativeName;
}
/**
* Creates a distribution point name from its DER-encoded form.
*
* @param encoding the DER-encoded value.
* @throws IOException on decoding error.
*/
public DistributionPointName(DerValue encoding) throws IOException {
if (encoding.isContextSpecific(TAG_FULL_NAME) &&
encoding.isConstructed()) {
encoding.resetTag(DerValue.tag_Sequence);
fullName = new GeneralNames(encoding);
} else if (encoding.isContextSpecific(TAG_RELATIVE_NAME) &&
encoding.isConstructed()) {
encoding.resetTag(DerValue.tag_Set);
relativeName = new RDN(encoding);
} else {
throw new IOException("Invalid encoding for DistributionPointName");
}
}
/**
* Returns the full name for the distribution point or null if not set.
*/
public GeneralNames getFullName() {
return fullName;
}
/**
* Returns the relative name for the distribution point or null if not set.
*/
public RDN getRelativeName() {
return relativeName;
}
/**
* Encodes the distribution point name and writes it to the DerOutputStream.
*
* @param out the output stream.
* @exception IOException on encoding error.
*/
public void encode(DerOutputStream out) throws IOException {
DerOutputStream theChoice = new DerOutputStream();
if (fullName != null) {
fullName.encode(theChoice);
out.writeImplicit(
DerValue.createTag(DerValue.TAG_CONTEXT, true, TAG_FULL_NAME),
theChoice);
} else {
relativeName.encode(theChoice);
out.writeImplicit(
DerValue.createTag(DerValue.TAG_CONTEXT, true,
TAG_RELATIVE_NAME),
theChoice);
}
}
/**
* Compare an object to this distribution point name for equality.
*
* @param obj Object to be compared to this
* @return true if objects match; false otherwise
*/
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof DistributionPointName == false) {
return false;
}
DistributionPointName other = (DistributionPointName)obj;
return Objects.equals(this.fullName, other.fullName) &&
Objects.equals(this.relativeName, other.relativeName);
}
/**
* Returns the hash code for this distribution point name.
*
* @return the hash code.
*/
public int hashCode() {
int hash = hashCode;
if (hash == 0) {
hash = 1;
if (fullName != null) {
hash += fullName.hashCode();
} else {
hash += relativeName.hashCode();
}
hashCode = hash;
}
return hash;
}
/**
* Returns a printable string of the distribution point name.
*/
public String toString() {
StringBuilder sb = new StringBuilder();
if (fullName != null) {
sb.append("DistributionPointName:\n " + fullName + "\n");
} else {
sb.append("DistributionPointName:\n " + relativeName + "\n");
}
return sb.toString();
}
}

View File

@@ -0,0 +1,257 @@
/*
* Copyright (c) 1997, 2004, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import sun.security.util.*;
/**
* This class defines the EDIPartyName of the GeneralName choice.
* The ASN.1 syntax for this is:
* <pre>
* EDIPartyName ::= SEQUENCE {
* nameAssigner [0] DirectoryString OPTIONAL,
* partyName [1] DirectoryString }
* </pre>
*
* @author Hemma Prafullchandra
* @see GeneralName
* @see GeneralNames
* @see GeneralNameInterface
*/
public class EDIPartyName implements GeneralNameInterface {
// Private data members
private static final byte TAG_ASSIGNER = 0;
private static final byte TAG_PARTYNAME = 1;
private String assigner = null;
private String party = null;
private int myhash = -1;
/**
* Create the EDIPartyName object from the specified names.
*
* @param assignerName the name of the assigner
* @param partyName the name of the EDI party.
*/
public EDIPartyName(String assignerName, String partyName) {
this.assigner = assignerName;
this.party = partyName;
}
/**
* Create the EDIPartyName object from the specified name.
*
* @param partyName the name of the EDI party.
*/
public EDIPartyName(String partyName) {
this.party = partyName;
}
/**
* Create the EDIPartyName object from the passed encoded Der value.
*
* @param derValue the encoded DER EDIPartyName.
* @exception IOException on error.
*/
public EDIPartyName(DerValue derValue) throws IOException {
DerInputStream in = new DerInputStream(derValue.toByteArray());
DerValue[] seq = in.getSequence(2);
int len = seq.length;
if (len < 1 || len > 2)
throw new IOException("Invalid encoding of EDIPartyName");
for (int i = 0; i < len; i++) {
DerValue opt = seq[i];
if (opt.isContextSpecific(TAG_ASSIGNER) &&
!opt.isConstructed()) {
if (assigner != null)
throw new IOException("Duplicate nameAssigner found in"
+ " EDIPartyName");
opt = opt.data.getDerValue();
assigner = opt.getAsString();
}
if (opt.isContextSpecific(TAG_PARTYNAME) &&
!opt.isConstructed()) {
if (party != null)
throw new IOException("Duplicate partyName found in"
+ " EDIPartyName");
opt = opt.data.getDerValue();
party = opt.getAsString();
}
}
}
/**
* Return the type of the GeneralName.
*/
public int getType() {
return (GeneralNameInterface.NAME_EDI);
}
/**
* Encode the EDI party name into the DerOutputStream.
*
* @param out the DER stream to encode the EDIPartyName to.
* @exception IOException on encoding errors.
*/
public void encode(DerOutputStream out) throws IOException {
DerOutputStream tagged = new DerOutputStream();
DerOutputStream tmp = new DerOutputStream();
if (assigner != null) {
DerOutputStream tmp2 = new DerOutputStream();
// XXX - shd check is chars fit into PrintableString
tmp2.putPrintableString(assigner);
tagged.write(DerValue.createTag(DerValue.TAG_CONTEXT,
false, TAG_ASSIGNER), tmp2);
}
if (party == null)
throw new IOException("Cannot have null partyName");
// XXX - shd check is chars fit into PrintableString
tmp.putPrintableString(party);
tagged.write(DerValue.createTag(DerValue.TAG_CONTEXT,
false, TAG_PARTYNAME), tmp);
out.write(DerValue.tag_Sequence, tagged);
}
/**
* Return the assignerName
*
* @returns String assignerName
*/
public String getAssignerName() {
return assigner;
}
/**
* Return the partyName
*
* @returns String partyName
*/
public String getPartyName() {
return party;
}
/**
* Compare this EDIPartyName with another. Does a byte-string
* comparison without regard to type of the partyName and
* the assignerName.
*
* @returns true if the two names match
*/
public boolean equals(Object other) {
if (!(other instanceof EDIPartyName))
return false;
String otherAssigner = ((EDIPartyName)other).assigner;
if (this.assigner == null) {
if (otherAssigner != null)
return false;
} else {
if (!(this.assigner.equals(otherAssigner)))
return false;
}
String otherParty = ((EDIPartyName)other).party;
if (this.party == null) {
if (otherParty != null)
return false;
} else {
if (!(this.party.equals(otherParty)))
return false;
}
return true;
}
/**
* Returns the hash code value for this EDIPartyName.
*
* @return a hash code value.
*/
public int hashCode() {
if (myhash == -1) {
myhash = 37 + (party == null ? 1 : party.hashCode());
if (assigner != null) {
myhash = 37 * myhash + assigner.hashCode();
}
}
return myhash;
}
/**
* Return the printable string.
*/
public String toString() {
return ("EDIPartyName: " +
((assigner == null) ? "" :
(" nameAssigner = " + assigner + ","))
+ " partyName = " + party);
}
/**
* Return constraint type:<ul>
* <li>NAME_DIFF_TYPE = -1: input name is different type from name (i.e. does not constrain)
* <li>NAME_MATCH = 0: input name matches name
* <li>NAME_NARROWS = 1: input name narrows name
* <li>NAME_WIDENS = 2: input name widens name
* <li>NAME_SAME_TYPE = 3: input name does not match or narrow name, but is same type
* </ul>. These results are used in checking NameConstraints during
* certification path verification.
*
* @param inputName to be checked for being constrained
* @returns constraint type above
* @throws UnsupportedOperationException if name is same type, but comparison operations are
* not supported for this name type.
*/
public int constrains(GeneralNameInterface inputName) throws UnsupportedOperationException {
int constraintType;
if (inputName == null)
constraintType = NAME_DIFF_TYPE;
else if (inputName.getType() != NAME_EDI)
constraintType = NAME_DIFF_TYPE;
else {
throw new UnsupportedOperationException("Narrowing, widening, and matching of names not supported for EDIPartyName");
}
return constraintType;
}
/**
* Return subtree depth of this name for purposes of determining
* NameConstraints minimum and maximum bounds and for calculating
* path lengths in name subtrees.
*
* @returns distance of name from root
* @throws UnsupportedOperationException if not supported for this name type
*/
public int subtreeDepth() throws UnsupportedOperationException {
throw new UnsupportedOperationException("subtreeDepth() not supported for EDIPartyName");
}
}

View File

@@ -0,0 +1,313 @@
/*
* Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import sun.security.util.DerValue;
import sun.security.util.DerOutputStream;
import sun.security.util.ObjectIdentifier;
/**
* This class defines the Extended Key Usage Extension, which
* indicates one or more purposes for which the certified public key
* may be used, in addition to or in place of the basic purposes
* indicated in the key usage extension field. This field is defined
* as follows:<p>
*
* id-ce-extKeyUsage OBJECT IDENTIFIER ::= {id-ce 37}<p>
*
* ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId<p>
*
* KeyPurposeId ::= OBJECT IDENTIFIER<p>
*
* Key purposes may be defined by any organization with a need. Object
* identifiers used to identify key purposes shall be assigned in
* accordance with IANA or ITU-T Rec. X.660 | ISO/IEC/ITU 9834-1.<p>
*
* This extension may, at the option of the certificate issuer, be
* either critical or non-critical.<p>
*
* If the extension is flagged critical, then the certificate MUST be
* used only for one of the purposes indicated.<p>
*
* If the extension is flagged non-critical, then it indicates the
* intended purpose or purposes of the key, and may be used in finding
* the correct key/certificate of an entity that has multiple
* keys/certificates. It is an advisory field and does not imply that
* usage of the key is restricted by the certification authority to
* the purpose indicated. Certificate using applications may
* nevertheless require that a particular purpose be indicated in
* order for the certificate to be acceptable to that application.<p>
* If a certificate contains both a critical key usage field and a
* critical extended key usage field, then both fields MUST be
* processed independently and the certificate MUST only be used for a
* purpose consistent with both fields. If there is no purpose
* consistent with both fields, then the certificate MUST NOT be used
* for any purpose.<p>
*
* @since 1.4
*/
public class ExtendedKeyUsageExtension extends Extension
implements CertAttrSet<String> {
/**
* Identifier for this attribute, to be used with the
* get, set, delete methods of Certificate, x509 type.
*/
public static final String IDENT = "x509.info.extensions.ExtendedKeyUsage";
/**
* Attribute names.
*/
public static final String NAME = "ExtendedKeyUsage";
public static final String USAGES = "usages";
// OID defined in RFC 5280 Sections 4.2.1.12
// more from http://www.alvestrand.no/objectid/1.3.6.1.5.5.7.3.html
private static final Map <ObjectIdentifier, String> map =
new HashMap <ObjectIdentifier, String> ();
private static final int[] anyExtendedKeyUsageOidData = {2, 5, 29, 37, 0};
private static final int[] serverAuthOidData = {1, 3, 6, 1, 5, 5, 7, 3, 1};
private static final int[] clientAuthOidData = {1, 3, 6, 1, 5, 5, 7, 3, 2};
private static final int[] codeSigningOidData = {1, 3, 6, 1, 5, 5, 7, 3, 3};
private static final int[] emailProtectionOidData = {1, 3, 6, 1, 5, 5, 7, 3, 4};
private static final int[] ipsecEndSystemOidData = {1, 3, 6, 1, 5, 5, 7, 3, 5};
private static final int[] ipsecTunnelOidData = {1, 3, 6, 1, 5, 5, 7, 3, 6};
private static final int[] ipsecUserOidData = {1, 3, 6, 1, 5, 5, 7, 3, 7};
private static final int[] timeStampingOidData = {1, 3, 6, 1, 5, 5, 7, 3, 8};
private static final int[] OCSPSigningOidData = {1, 3, 6, 1, 5, 5, 7, 3, 9};
static {
map.put(ObjectIdentifier.newInternal(anyExtendedKeyUsageOidData), "anyExtendedKeyUsage");
map.put(ObjectIdentifier.newInternal(serverAuthOidData), "serverAuth");
map.put(ObjectIdentifier.newInternal(clientAuthOidData), "clientAuth");
map.put(ObjectIdentifier.newInternal(codeSigningOidData), "codeSigning");
map.put(ObjectIdentifier.newInternal(emailProtectionOidData), "emailProtection");
map.put(ObjectIdentifier.newInternal(ipsecEndSystemOidData), "ipsecEndSystem");
map.put(ObjectIdentifier.newInternal(ipsecTunnelOidData), "ipsecTunnel");
map.put(ObjectIdentifier.newInternal(ipsecUserOidData), "ipsecUser");
map.put(ObjectIdentifier.newInternal(timeStampingOidData), "timeStamping");
map.put(ObjectIdentifier.newInternal(OCSPSigningOidData), "OCSPSigning");
};
/**
* Vector of KeyUsages for this object.
*/
private Vector<ObjectIdentifier> keyUsages;
// Encode this extension value.
private void encodeThis() throws IOException {
if (keyUsages == null || keyUsages.isEmpty()) {
this.extensionValue = null;
return;
}
DerOutputStream os = new DerOutputStream();
DerOutputStream tmp = new DerOutputStream();
for (int i = 0; i < keyUsages.size(); i++) {
tmp.putOID(keyUsages.elementAt(i));
}
os.write(DerValue.tag_Sequence, tmp);
this.extensionValue = os.toByteArray();
}
/**
* Create a ExtendedKeyUsageExtension object from
* a Vector of Key Usages; the criticality is set to false.
*
* @param keyUsages the Vector of KeyUsages (ObjectIdentifiers)
*/
public ExtendedKeyUsageExtension(Vector<ObjectIdentifier> keyUsages)
throws IOException {
this(Boolean.FALSE, keyUsages);
}
/**
* Create a ExtendedKeyUsageExtension object from
* a Vector of KeyUsages with specified criticality.
*
* @param critical true if the extension is to be treated as critical.
* @param keyUsages the Vector of KeyUsages (ObjectIdentifiers)
*/
public ExtendedKeyUsageExtension(Boolean critical, Vector<ObjectIdentifier> keyUsages)
throws IOException {
this.keyUsages = keyUsages;
this.extensionId = PKIXExtensions.ExtendedKeyUsage_Id;
this.critical = critical.booleanValue();
encodeThis();
}
/**
* Create the extension from its DER encoded value and criticality.
*
* @param critical true if the extension is to be treated as critical.
* @param value an array of DER encoded bytes of the actual value.
* @exception ClassCastException if value is not an array of bytes
* @exception IOException on error.
*/
public ExtendedKeyUsageExtension(Boolean critical, Object value)
throws IOException {
this.extensionId = PKIXExtensions.ExtendedKeyUsage_Id;
this.critical = critical.booleanValue();
this.extensionValue = (byte[]) value;
DerValue val = new DerValue(this.extensionValue);
if (val.tag != DerValue.tag_Sequence) {
throw new IOException("Invalid encoding for " +
"ExtendedKeyUsageExtension.");
}
keyUsages = new Vector<ObjectIdentifier>();
while (val.data.available() != 0) {
DerValue seq = val.data.getDerValue();
ObjectIdentifier usage = seq.getOID();
keyUsages.addElement(usage);
}
}
/**
* Return the extension as user readable string.
*/
public String toString() {
if (keyUsages == null) return "";
String usage = " ";
boolean first = true;
for (ObjectIdentifier oid: keyUsages) {
if(!first) {
usage += "\n ";
}
String result = map.get(oid);
if (result != null) {
usage += result;
} else {
usage += oid.toString();
}
first = false;
}
return super.toString() + "ExtendedKeyUsages [\n"
+ usage + "\n]\n";
}
/**
* Write the extension to the DerOutputStream.
*
* @param out the DerOutputStream to write the extension to.
* @exception IOException on encoding errors.
*/
public void encode(OutputStream out) throws IOException {
DerOutputStream tmp = new DerOutputStream();
if (extensionValue == null) {
extensionId = PKIXExtensions.ExtendedKeyUsage_Id;
critical = false;
encodeThis();
}
super.encode(tmp);
out.write(tmp.toByteArray());
}
/**
* Set the attribute value.
*/
@SuppressWarnings("unchecked") // Checked with instanceof
public void set(String name, Object obj) throws IOException {
if (name.equalsIgnoreCase(USAGES)) {
if (!(obj instanceof Vector)) {
throw new IOException("Attribute value should be of type Vector.");
}
this.keyUsages = (Vector<ObjectIdentifier>)obj;
} else {
throw new IOException("Attribute name [" + name +
"] not recognized by " +
"CertAttrSet:ExtendedKeyUsageExtension.");
}
encodeThis();
}
/**
* Get the attribute value.
*/
public Vector<ObjectIdentifier> get(String name) throws IOException {
if (name.equalsIgnoreCase(USAGES)) {
//XXXX May want to consider cloning this
return keyUsages;
} else {
throw new IOException("Attribute name [" + name +
"] not recognized by " +
"CertAttrSet:ExtendedKeyUsageExtension.");
}
}
/**
* Delete the attribute value.
*/
public void delete(String name) throws IOException {
if (name.equalsIgnoreCase(USAGES)) {
keyUsages = null;
} else {
throw new IOException("Attribute name [" + name +
"] not recognized by " +
"CertAttrSet:ExtendedKeyUsageExtension.");
}
encodeThis();
}
/**
* Return an enumeration of names of attributes existing within this
* attribute.
*/
public Enumeration<String> getElements() {
AttributeNameEnumeration elements = new AttributeNameEnumeration();
elements.addElement(USAGES);
return (elements.elements());
}
/**
* Return the name of this attribute.
*/
public String getName() {
return (NAME);
}
public List<String> getExtendedKeyUsage() {
List<String> al = new ArrayList<String>(keyUsages.size());
for (ObjectIdentifier oid : keyUsages) {
al.add(oid.toString());
}
return al;
}
}

View File

@@ -0,0 +1,276 @@
/*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Arrays;
import sun.security.util.*;
/**
* Represent a X509 Extension Attribute.
*
* <p>Extensions are additional attributes which can be inserted in a X509
* v3 certificate. For example a "Driving License Certificate" could have
* the driving license number as a extension.
*
* <p>Extensions are represented as a sequence of the extension identifier
* (Object Identifier), a boolean flag stating whether the extension is to
* be treated as being critical and the extension value itself (this is again
* a DER encoding of the extension value).
* <pre>
* ASN.1 definition of Extension:
* Extension ::= SEQUENCE {
* ExtensionId OBJECT IDENTIFIER,
* critical BOOLEAN DEFAULT FALSE,
* extensionValue OCTET STRING
* }
* </pre>
* All subclasses need to implement a constructor of the form
* <pre>
* <subclass> (Boolean, Object)
* </pre>
* where the Object is typically an array of DER encoded bytes.
* <p>
* @author Amit Kapoor
* @author Hemma Prafullchandra
*/
public class Extension implements java.security.cert.Extension {
protected ObjectIdentifier extensionId = null;
protected boolean critical = false;
protected byte[] extensionValue = null;
/**
* Default constructor. Used only by sub-classes.
*/
public Extension() { }
/**
* Constructs an extension from a DER encoded array of bytes.
*/
public Extension(DerValue derVal) throws IOException {
DerInputStream in = derVal.toDerInputStream();
// Object identifier
extensionId = in.getOID();
// If the criticality flag was false, it will not have been encoded.
DerValue val = in.getDerValue();
if (val.tag == DerValue.tag_Boolean) {
critical = val.getBoolean();
// Extension value (DER encoded)
val = in.getDerValue();
extensionValue = val.getOctetString();
} else {
critical = false;
extensionValue = val.getOctetString();
}
}
/**
* Constructs an Extension from individual components of ObjectIdentifier,
* criticality and the DER encoded OctetString.
*
* @param extensionId the ObjectIdentifier of the extension
* @param critical the boolean indicating if the extension is critical
* @param extensionValue the DER encoded octet string of the value.
*/
public Extension(ObjectIdentifier extensionId, boolean critical,
byte[] extensionValue) throws IOException {
this.extensionId = extensionId;
this.critical = critical;
// passed in a DER encoded octet string, strip off the tag
// and length
DerValue inDerVal = new DerValue(extensionValue);
this.extensionValue = inDerVal.getOctetString();
}
/**
* Constructs an Extension from another extension. To be used for
* creating decoded subclasses.
*
* @param ext the extension to create from.
*/
public Extension(Extension ext) {
this.extensionId = ext.extensionId;
this.critical = ext.critical;
this.extensionValue = ext.extensionValue;
}
/**
* Constructs an Extension from individual components of ObjectIdentifier,
* criticality and the raw encoded extension value.
*
* @param extensionId the ObjectIdentifier of the extension
* @param critical the boolean indicating if the extension is critical
* @param rawExtensionValue the raw DER-encoded extension value (this
* is not the encoded OctetString).
*/
public static Extension newExtension(ObjectIdentifier extensionId,
boolean critical, byte[] rawExtensionValue) throws IOException {
Extension ext = new Extension();
ext.extensionId = extensionId;
ext.critical = critical;
ext.extensionValue = rawExtensionValue;
return ext;
}
public void encode(OutputStream out) throws IOException {
if (out == null) {
throw new NullPointerException();
}
DerOutputStream dos1 = new DerOutputStream();
DerOutputStream dos2 = new DerOutputStream();
dos1.putOID(extensionId);
if (critical) {
dos1.putBoolean(critical);
}
dos1.putOctetString(extensionValue);
dos2.write(DerValue.tag_Sequence, dos1);
out.write(dos2.toByteArray());
}
/**
* Write the extension to the DerOutputStream.
*
* @param out the DerOutputStream to write the extension to.
* @exception IOException on encoding errors
*/
public void encode(DerOutputStream out) throws IOException {
if (extensionId == null)
throw new IOException("Null OID to encode for the extension!");
if (extensionValue == null)
throw new IOException("No value to encode for the extension!");
DerOutputStream dos = new DerOutputStream();
dos.putOID(extensionId);
if (critical)
dos.putBoolean(critical);
dos.putOctetString(extensionValue);
out.write(DerValue.tag_Sequence, dos);
}
/**
* Returns true if extension is critical.
*/
public boolean isCritical() {
return critical;
}
/**
* Returns the ObjectIdentifier of the extension.
*/
public ObjectIdentifier getExtensionId() {
return extensionId;
}
public byte[] getValue() {
return extensionValue.clone();
}
/**
* Returns the extension value as an byte array for further processing.
* Note, this is the raw DER value of the extension, not the DER
* encoded octet string which is in the certificate.
* This method does not return a clone; it is the responsibility of the
* caller to clone the array if necessary.
*/
public byte[] getExtensionValue() {
return extensionValue;
}
public String getId() {
return extensionId.toString();
}
/**
* Returns the Extension in user readable form.
*/
public String toString() {
String s = "ObjectId: " + extensionId.toString();
if (critical) {
s += " Criticality=true\n";
} else {
s += " Criticality=false\n";
}
return (s);
}
// Value to mix up the hash
private static final int hashMagic = 31;
/**
* Returns a hashcode value for this Extension.
*
* @return the hashcode value.
*/
public int hashCode() {
int h = 0;
if (extensionValue != null) {
byte[] val = extensionValue;
int len = val.length;
while (len > 0)
h += len * val[--len];
}
h = h * hashMagic + extensionId.hashCode();
h = h * hashMagic + (critical?1231:1237);
return h;
}
/**
* Compares this Extension for equality with the specified
* object. If the <code>other</code> object is an
* <code>instanceof</code> <code>Extension</code>, then
* its encoded form is retrieved and compared with the
* encoded form of this Extension.
*
* @param other the object to test for equality with this Extension.
* @return true iff the other object is of type Extension, and the
* criticality flag, object identifier and encoded extension value of
* the two Extensions match, false otherwise.
*/
public boolean equals(Object other) {
if (this == other)
return true;
if (!(other instanceof Extension))
return false;
Extension otherExt = (Extension) other;
if (critical != otherExt.critical)
return false;
if (!extensionId.equals((Object)otherExt.extensionId))
return false;
return Arrays.equals(extensionValue, otherExt.extensionValue);
}
}

View File

@@ -0,0 +1,99 @@
/*
* Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.io.OutputStream;
import java.math.BigInteger;
import java.util.Enumeration;
import java.util.List;
import sun.security.util.*;
/**
* Represents the Freshest CRL Extension.
*
* <p>
* The extension identifies how delta CRL information for a
* complete CRL is obtained.
*
* <p>
* The extension is defined in Section 5.2.6 of
* <a href="http://tools.ietf.org/html/rfc5280">Internet X.509 PKI Certific
ate and Certificate Revocation List (CRL) Profile</a>.
*
* <p>
* Its ASN.1 definition is as follows:
* <pre>
* id-ce-freshestCRL OBJECT IDENTIFIER ::= { id-ce 46 }
*
* FreshestCRL ::= CRLDistributionPoints
* </pre>
*
* @since 1.6
*/
public class FreshestCRLExtension extends CRLDistributionPointsExtension {
/**
* Attribute name.
*/
public static final String NAME = "FreshestCRL";
/**
* Creates a freshest CRL extension.
* The criticality is set to false.
*
* @param distributionPoints the list of delta CRL distribution points.
*/
public FreshestCRLExtension(List<DistributionPoint> distributionPoints)
throws IOException {
super(PKIXExtensions.FreshestCRL_Id, false, distributionPoints, NAME);
}
/**
* Creates the extension from the passed DER encoded value of the same.
*
* @param critical true if the extension is to be treated as critical.
* @param value an array of DER encoded bytes of the actual value.
* @exception IOException on decoding error.
*/
public FreshestCRLExtension(Boolean critical, Object value)
throws IOException {
super(PKIXExtensions.FreshestCRL_Id, critical.booleanValue(), value,
NAME);
}
/**
* Writes the extension to the DerOutputStream.
*
* @param out the DerOutputStream to write the extension to.
* @exception IOException on encoding errors.
*/
public void encode(OutputStream out) throws IOException {
super.encode(out, PKIXExtensions.FreshestCRL_Id, false);
}
}

View File

@@ -0,0 +1,249 @@
/*
* Copyright (c) 1997, 2004, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import sun.security.util.*;
/**
* This class implements the ASN.1 GeneralName object class.
* <p>
* The ASN.1 syntax for this is:
* <pre>
* GeneralName ::= CHOICE {
* otherName [0] OtherName,
* rfc822Name [1] IA5String,
* dNSName [2] IA5String,
* x400Address [3] ORAddress,
* directoryName [4] Name,
* ediPartyName [5] EDIPartyName,
* uniformResourceIdentifier [6] IA5String,
* iPAddress [7] OCTET STRING,
* registeredID [8] OBJECT IDENTIFIER
* }
* </pre>
* @author Amit Kapoor
* @author Hemma Prafullchandra
*/
public class GeneralName {
// Private data members
private GeneralNameInterface name = null;
/**
* Default constructor for the class.
*
* @param name the selected CHOICE from the list.
* @throws NullPointerException if name is null
*/
public GeneralName(GeneralNameInterface name) {
if (name == null) {
throw new NullPointerException("GeneralName must not be null");
}
this.name = name;
}
/**
* Create the object from its DER encoded value.
*
* @param encName the DER encoded GeneralName.
*/
public GeneralName(DerValue encName) throws IOException {
this(encName, false);
}
/**
* Create the object from its DER encoded value.
*
* @param encName the DER encoded GeneralName.
* @param nameConstraint true if general name is a name constraint
*/
public GeneralName(DerValue encName, boolean nameConstraint)
throws IOException {
short tag = (byte)(encName.tag & 0x1f);
// All names except for NAME_DIRECTORY should be encoded with the
// IMPLICIT tag.
switch (tag) {
case GeneralNameInterface.NAME_ANY:
if (encName.isContextSpecific() && encName.isConstructed()) {
encName.resetTag(DerValue.tag_Sequence);
name = new OtherName(encName);
} else {
throw new IOException("Invalid encoding of Other-Name");
}
break;
case GeneralNameInterface.NAME_RFC822:
if (encName.isContextSpecific() && !encName.isConstructed()) {
encName.resetTag(DerValue.tag_IA5String);
name = new RFC822Name(encName);
} else {
throw new IOException("Invalid encoding of RFC822 name");
}
break;
case GeneralNameInterface.NAME_DNS:
if (encName.isContextSpecific() && !encName.isConstructed()) {
encName.resetTag(DerValue.tag_IA5String);
name = new DNSName(encName);
} else {
throw new IOException("Invalid encoding of DNSName");
}
break;
case GeneralNameInterface.NAME_URI:
if (encName.isContextSpecific() && !encName.isConstructed()) {
encName.resetTag(DerValue.tag_IA5String);
name = (nameConstraint ? URIName.nameConstraint(encName) :
new URIName(encName));
} else {
throw new IOException("Invalid encoding of URI");
}
break;
case GeneralNameInterface.NAME_IP:
if (encName.isContextSpecific() && !encName.isConstructed()) {
encName.resetTag(DerValue.tag_OctetString);
name = new IPAddressName(encName);
} else {
throw new IOException("Invalid encoding of IP address");
}
break;
case GeneralNameInterface.NAME_OID:
if (encName.isContextSpecific() && !encName.isConstructed()) {
encName.resetTag(DerValue.tag_ObjectId);
name = new OIDName(encName);
} else {
throw new IOException("Invalid encoding of OID name");
}
break;
case GeneralNameInterface.NAME_DIRECTORY:
if (encName.isContextSpecific() && encName.isConstructed()) {
name = new X500Name(encName.getData());
} else {
throw new IOException("Invalid encoding of Directory name");
}
break;
case GeneralNameInterface.NAME_EDI:
if (encName.isContextSpecific() && encName.isConstructed()) {
encName.resetTag(DerValue.tag_Sequence);
name = new EDIPartyName(encName);
} else {
throw new IOException("Invalid encoding of EDI name");
}
break;
default:
throw new IOException("Unrecognized GeneralName tag, ("
+ tag +")");
}
}
/**
* Return the type of the general name.
*/
public int getType() {
return name.getType();
}
/**
* Return the GeneralNameInterface name.
*/
public GeneralNameInterface getName() {
//XXXX May want to consider cloning this
return name;
}
/**
* Return the name as user readable string
*/
public String toString() {
return name.toString();
}
/**
* Compare this GeneralName with another
*
* @param other GeneralName to compare to this
* @returns true if match
*/
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof GeneralName))
return false;
GeneralNameInterface otherGNI = ((GeneralName)other).name;
try {
return name.constrains(otherGNI) == GeneralNameInterface.NAME_MATCH;
} catch (UnsupportedOperationException ioe) {
return false;
}
}
/**
* Returns the hash code for this GeneralName.
*
* @return a hash code value.
*/
public int hashCode() {
return name.hashCode();
}
/**
* Encode the name to the specified DerOutputStream.
*
* @param out the DerOutputStream to encode the the GeneralName to.
* @exception IOException on encoding errors.
*/
public void encode(DerOutputStream out) throws IOException {
DerOutputStream tmp = new DerOutputStream();
name.encode(tmp);
int nameType = name.getType();
if (nameType == GeneralNameInterface.NAME_ANY ||
nameType == GeneralNameInterface.NAME_X400 ||
nameType == GeneralNameInterface.NAME_EDI) {
// implicit, constructed form
out.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT,
true, (byte)nameType), tmp);
} else if (nameType == GeneralNameInterface.NAME_DIRECTORY) {
// explicit, constructed form since underlying tag is CHOICE
// (see X.680 section 30.6, part c)
out.write(DerValue.createTag(DerValue.TAG_CONTEXT,
true, (byte)nameType), tmp);
} else {
// implicit, primitive form
out.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT,
false, (byte)nameType), tmp);
}
}
}

View File

@@ -0,0 +1,103 @@
/*
* Copyright (c) 1997, 2000, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import sun.security.util.*;
/**
* This interface specifies the abstract methods which have to be
* implemented by all the members of the GeneralNames ASN.1 object.
*
* @author Amit Kapoor
* @author Hemma Prafullchandra
*/
public interface GeneralNameInterface {
/**
* The list of names supported.
*/
public static final int NAME_ANY = 0;
public static final int NAME_RFC822 = 1;
public static final int NAME_DNS = 2;
public static final int NAME_X400 = 3;
public static final int NAME_DIRECTORY = 4;
public static final int NAME_EDI = 5;
public static final int NAME_URI = 6;
public static final int NAME_IP = 7;
public static final int NAME_OID = 8;
/**
* The list of constraint results.
*/
public static final int NAME_DIFF_TYPE = -1; /* input name is different type from name (i.e. does not constrain) */
public static final int NAME_MATCH = 0; /* input name matches name */
public static final int NAME_NARROWS = 1; /* input name narrows name */
public static final int NAME_WIDENS = 2; /* input name widens name */
public static final int NAME_SAME_TYPE = 3; /* input name does not match, narrow, or widen, but is same type */
/**
* Return the type of the general name, as
* defined above.
*/
int getType();
/**
* Encode the name to the specified DerOutputStream.
*
* @param out the DerOutputStream to encode the GeneralName to.
* @exception IOException thrown if the GeneralName could not be
* encoded.
*/
void encode(DerOutputStream out) throws IOException;
/**
* Return type of constraint inputName places on this name:<ul>
* <li>NAME_DIFF_TYPE = -1: input name is different type from name (i.e. does not constrain).
* <li>NAME_MATCH = 0: input name matches name.
* <li>NAME_NARROWS = 1: input name narrows name (is lower in the naming subtree)
* <li>NAME_WIDENS = 2: input name widens name (is higher in the naming subtree)
* <li>NAME_SAME_TYPE = 3: input name does not match or narrow name, but is same type.
* </ul>. These results are used in checking NameConstraints during
* certification path verification.
*
* @param inputName to be checked for being constrained
* @returns constraint type above
* @throws UnsupportedOperationException if name is same type, but comparison operations are
* not supported for this name type.
*/
int constrains(GeneralNameInterface inputName) throws UnsupportedOperationException;
/**
* Return subtree depth of this name for purposes of determining
* NameConstraints minimum and maximum bounds and for calculating
* path lengths in name subtrees.
*
* @returns distance of name from root
* @throws UnsupportedOperationException if not supported for this name type
*/
int subtreeDepth() throws UnsupportedOperationException;
}

View File

@@ -0,0 +1,150 @@
/*
* Copyright (c) 1997, 2003, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.util.*;
import java.io.IOException;
import sun.security.util.*;
/**
* This object class represents the GeneralNames type required in
* X509 certificates.
* <p>The ASN.1 syntax for this is:
* <pre>
* GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
* </pre>
*
* @author Amit Kapoor
* @author Hemma Prafullchandra
*
*/
public class GeneralNames {
private final List<GeneralName> names;
/**
* Create the GeneralNames, decoding from the passed DerValue.
*
* @param derVal the DerValue to construct the GeneralNames from.
* @exception IOException on error.
*/
public GeneralNames(DerValue derVal) throws IOException {
this();
if (derVal.tag != DerValue.tag_Sequence) {
throw new IOException("Invalid encoding for GeneralNames.");
}
if (derVal.data.available() == 0) {
throw new IOException("No data available in "
+ "passed DER encoded value.");
}
// Decode all the GeneralName's
while (derVal.data.available() != 0) {
DerValue encName = derVal.data.getDerValue();
GeneralName name = new GeneralName(encName);
add(name);
}
}
/**
* The default constructor for this class.
*/
public GeneralNames() {
names = new ArrayList<GeneralName>();
}
public GeneralNames add(GeneralName name) {
if (name == null) {
throw new NullPointerException();
}
names.add(name);
return this;
}
public GeneralName get(int index) {
return names.get(index);
}
public boolean isEmpty() {
return names.isEmpty();
}
public int size() {
return names.size();
}
public Iterator<GeneralName> iterator() {
return names.iterator();
}
public List<GeneralName> names() {
return names;
}
/**
* Write the extension to the DerOutputStream.
*
* @param out the DerOutputStream to write the extension to.
* @exception IOException on error.
*/
public void encode(DerOutputStream out) throws IOException {
if (isEmpty()) {
return;
}
DerOutputStream temp = new DerOutputStream();
for (GeneralName gn : names) {
gn.encode(temp);
}
out.write(DerValue.tag_Sequence, temp);
}
/**
* compare this GeneralNames to other object for equality
*
* @returns true iff this equals other
*/
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof GeneralNames == false) {
return false;
}
GeneralNames other = (GeneralNames)obj;
return this.names.equals(other.names);
}
public int hashCode() {
return names.hashCode();
}
public String toString() {
return names.toString();
}
}

View File

@@ -0,0 +1,211 @@
/*
* Copyright (c) 1997, 2004, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.*;
import sun.security.util.*;
/**
* Represent the GeneralSubtree ASN.1 object, whose syntax is:
* <pre>
* GeneralSubtree ::= SEQUENCE {
* base GeneralName,
* minimum [0] BaseDistance DEFAULT 0,
* maximum [1] BaseDistance OPTIONAL
* }
* BaseDistance ::= INTEGER (0..MAX)
* </pre>
* @author Amit Kapoor
* @author Hemma Prafullchandra
*/
public class GeneralSubtree {
private static final byte TAG_MIN = 0;
private static final byte TAG_MAX = 1;
private static final int MIN_DEFAULT = 0;
private GeneralName name;
private int minimum = MIN_DEFAULT;
private int maximum = -1;
private int myhash = -1;
/**
* The default constructor for the class.
*
* @params name the GeneralName
* @params min the minimum BaseDistance
* @params max the maximum BaseDistance
*/
public GeneralSubtree(GeneralName name, int min, int max) {
this.name = name;
this.minimum = min;
this.maximum = max;
}
/**
* Create the object from its DER encoded form.
*
* @param val the DER encoded from of the same.
*/
public GeneralSubtree(DerValue val) throws IOException {
if (val.tag != DerValue.tag_Sequence) {
throw new IOException("Invalid encoding for GeneralSubtree.");
}
name = new GeneralName(val.data.getDerValue(), true);
// NB. this is always encoded with the IMPLICIT tag
// The checks only make sense if we assume implicit tagging,
// with explicit tagging the form is always constructed.
while (val.data.available() != 0) {
DerValue opt = val.data.getDerValue();
if (opt.isContextSpecific(TAG_MIN) && !opt.isConstructed()) {
opt.resetTag(DerValue.tag_Integer);
minimum = opt.getInteger();
} else if (opt.isContextSpecific(TAG_MAX) && !opt.isConstructed()) {
opt.resetTag(DerValue.tag_Integer);
maximum = opt.getInteger();
} else
throw new IOException("Invalid encoding of GeneralSubtree.");
}
}
/**
* Return the GeneralName.
*
* @return the GeneralName
*/
public GeneralName getName() {
//XXXX May want to consider cloning this
return name;
}
/**
* Return the minimum BaseDistance.
*
* @return the minimum BaseDistance. Default is 0 if not set.
*/
public int getMinimum() {
return minimum;
}
/**
* Return the maximum BaseDistance.
*
* @return the maximum BaseDistance, or -1 if not set.
*/
public int getMaximum() {
return maximum;
}
/**
* Return a printable string of the GeneralSubtree.
*/
public String toString() {
String s = "\n GeneralSubtree: [\n" +
" GeneralName: " + ((name == null) ? "" : name.toString()) +
"\n Minimum: " + minimum;
if (maximum == -1) {
s += "\t Maximum: undefined";
} else
s += "\t Maximum: " + maximum;
s += " ]\n";
return (s);
}
/**
* Compare this GeneralSubtree with another
*
* @param other GeneralSubtree to compare to this
* @returns true if match
*/
public boolean equals(Object other) {
if (!(other instanceof GeneralSubtree))
return false;
GeneralSubtree otherGS = (GeneralSubtree)other;
if (this.name == null) {
if (otherGS.name != null) {
return false;
}
} else {
if (!((this.name).equals(otherGS.name)))
return false;
}
if (this.minimum != otherGS.minimum)
return false;
if (this.maximum != otherGS.maximum)
return false;
return true;
}
/**
* Returns the hash code for this GeneralSubtree.
*
* @return a hash code value.
*/
public int hashCode() {
if (myhash == -1) {
myhash = 17;
if (name != null) {
myhash = 37 * myhash + name.hashCode();
}
if (minimum != MIN_DEFAULT) {
myhash = 37 * myhash + minimum;
}
if (maximum != -1) {
myhash = 37 * myhash + maximum;
}
}
return myhash;
}
/**
* Encode the GeneralSubtree.
*
* @params out the DerOutputStream to encode this object to.
*/
public void encode(DerOutputStream out) throws IOException {
DerOutputStream seq = new DerOutputStream();
name.encode(seq);
if (minimum != MIN_DEFAULT) {
DerOutputStream tmp = new DerOutputStream();
tmp.putInteger(minimum);
seq.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT,
false, TAG_MIN), tmp);
}
if (maximum != -1) {
DerOutputStream tmp = new DerOutputStream();
tmp.putInteger(maximum);
seq.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT,
false, TAG_MAX), tmp);
}
out.write(DerValue.tag_Sequence, seq);
}
}

View File

@@ -0,0 +1,525 @@
/*
* Copyright (c) 1997, 2003, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.*;
import java.util.*;
import sun.security.util.*;
/**
* Represent the GeneralSubtrees ASN.1 object.
* <p>
* The ASN.1 for this is
* <pre>
* GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
* </pre>
* </p>
*
*
* @author Amit Kapoor
* @author Hemma Prafullchandra
* @author Andreas Sterbenz
*/
public class GeneralSubtrees implements Cloneable {
private final List<GeneralSubtree> trees;
// Private variables
private static final int NAME_DIFF_TYPE = GeneralNameInterface.NAME_DIFF_TYPE;
private static final int NAME_MATCH = GeneralNameInterface.NAME_MATCH;
private static final int NAME_NARROWS = GeneralNameInterface.NAME_NARROWS;
private static final int NAME_WIDENS = GeneralNameInterface.NAME_WIDENS;
private static final int NAME_SAME_TYPE = GeneralNameInterface.NAME_SAME_TYPE;
/**
* The default constructor for the class.
*/
public GeneralSubtrees() {
trees = new ArrayList<GeneralSubtree>();
}
private GeneralSubtrees(GeneralSubtrees source) {
trees = new ArrayList<GeneralSubtree>(source.trees);
}
/**
* Create the object from the passed DER encoded form.
*
* @param val the DER encoded form of the same.
*/
public GeneralSubtrees(DerValue val) throws IOException {
this();
if (val.tag != DerValue.tag_Sequence) {
throw new IOException("Invalid encoding of GeneralSubtrees.");
}
while (val.data.available() != 0) {
DerValue opt = val.data.getDerValue();
GeneralSubtree tree = new GeneralSubtree(opt);
add(tree);
}
}
public GeneralSubtree get(int index) {
return trees.get(index);
}
public void remove(int index) {
trees.remove(index);
}
public void add(GeneralSubtree tree) {
if (tree == null) {
throw new NullPointerException();
}
trees.add(tree);
}
public boolean contains(GeneralSubtree tree) {
if (tree == null) {
throw new NullPointerException();
}
return trees.contains(tree);
}
public int size() {
return trees.size();
}
public Iterator<GeneralSubtree> iterator() {
return trees.iterator();
}
public List<GeneralSubtree> trees() {
return trees;
}
public Object clone() {
return new GeneralSubtrees(this);
}
/**
* Return a printable string of the GeneralSubtree.
*/
public String toString() {
String s = " GeneralSubtrees:\n" + trees.toString() + "\n";
return s;
}
/**
* Encode the GeneralSubtrees.
*
* @params out the DerOutputStrean to encode this object to.
*/
public void encode(DerOutputStream out) throws IOException {
DerOutputStream seq = new DerOutputStream();
for (int i = 0, n = size(); i < n; i++) {
get(i).encode(seq);
}
out.write(DerValue.tag_Sequence, seq);
}
/**
* Compare two general subtrees by comparing the subtrees
* of each.
*
* @param other GeneralSubtrees to compare to this
* @returns true if match
*/
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof GeneralSubtrees == false) {
return false;
}
GeneralSubtrees other = (GeneralSubtrees)obj;
return this.trees.equals(other.trees);
}
public int hashCode() {
return trees.hashCode();
}
/**
* Return the GeneralNameInterface form of the GeneralName in one of
* the GeneralSubtrees.
*
* @param ndx index of the GeneralSubtree from which to obtain the name
*/
private GeneralNameInterface getGeneralNameInterface(int ndx) {
return getGeneralNameInterface(get(ndx));
}
private static GeneralNameInterface getGeneralNameInterface(GeneralSubtree gs) {
GeneralName gn = gs.getName();
GeneralNameInterface gni = gn.getName();
return gni;
}
/**
* minimize this GeneralSubtrees by removing all redundant entries.
* Internal method used by intersect and reduce.
*/
private void minimize() {
// Algorithm: compare each entry n to all subsequent entries in
// the list: if any subsequent entry matches or widens entry n,
// remove entry n. If any subsequent entries narrow entry n, remove
// the subsequent entries.
for (int i = 0; i < (size() - 1); i++) {
GeneralNameInterface current = getGeneralNameInterface(i);
boolean remove1 = false;
/* compare current to subsequent elements */
for (int j = i + 1; j < size(); j++) {
GeneralNameInterface subsequent = getGeneralNameInterface(j);
switch (current.constrains(subsequent)) {
case GeneralNameInterface.NAME_DIFF_TYPE:
/* not comparable; different name types; keep checking */
continue;
case GeneralNameInterface.NAME_MATCH:
/* delete one of the duplicates */
remove1 = true;
break;
case GeneralNameInterface.NAME_NARROWS:
/* subsequent narrows current */
/* remove narrower name (subsequent) */
remove(j);
j--; /* continue check with new subsequent */
continue;
case GeneralNameInterface.NAME_WIDENS:
/* subsequent widens current */
/* remove narrower name current */
remove1 = true;
break;
case GeneralNameInterface.NAME_SAME_TYPE:
/* keep both for now; keep checking */
continue;
}
break;
} /* end of this pass of subsequent elements */
if (remove1) {
remove(i);
i--; /* check the new i value */
}
}
}
/**
* create a subtree containing an instance of the input
* name type that widens all other names of that type.
*
* @params name GeneralNameInterface name
* @returns GeneralSubtree containing widest name of that type
* @throws RuntimeException on error (should not occur)
*/
private GeneralSubtree createWidestSubtree(GeneralNameInterface name) {
try {
GeneralName newName;
switch (name.getType()) {
case GeneralNameInterface.NAME_ANY:
// Create new OtherName with same OID as baseName, but
// empty value
ObjectIdentifier otherOID = ((OtherName)name).getOID();
newName = new GeneralName(new OtherName(otherOID, null));
break;
case GeneralNameInterface.NAME_RFC822:
newName = new GeneralName(new RFC822Name(""));
break;
case GeneralNameInterface.NAME_DNS:
newName = new GeneralName(new DNSName(""));
break;
case GeneralNameInterface.NAME_X400:
newName = new GeneralName(new X400Address((byte[])null));
break;
case GeneralNameInterface.NAME_DIRECTORY:
newName = new GeneralName(new X500Name(""));
break;
case GeneralNameInterface.NAME_EDI:
newName = new GeneralName(new EDIPartyName(""));
break;
case GeneralNameInterface.NAME_URI:
newName = new GeneralName(new URIName(""));
break;
case GeneralNameInterface.NAME_IP:
newName = new GeneralName(new IPAddressName((byte[])null));
break;
case GeneralNameInterface.NAME_OID:
newName = new GeneralName
(new OIDName(new ObjectIdentifier((int[])null)));
break;
default:
throw new IOException
("Unsupported GeneralNameInterface type: " + name.getType());
}
return new GeneralSubtree(newName, 0, -1);
} catch (IOException e) {
throw new RuntimeException("Unexpected error: " + e, e);
}
}
/**
* intersect this GeneralSubtrees with other. This function
* is used in merging permitted NameConstraints. The operation
* is performed as follows:
* <ul>
* <li>If a name in other narrows all names of the same type in this,
* the result will contain the narrower name and none of the
* names it narrows.
* <li>If a name in other widens all names of the same type in this,
* the result will not contain the wider name.
* <li>If a name in other does not share the same subtree with any name
* of the same type in this, then the name is added to the list
* of GeneralSubtrees returned. These names should be added to
* the list of names that are specifically excluded. The reason
* is that, if the intersection is empty, then no names of that
* type are permitted, and the only way to express this in
* NameConstraints is to include the name in excludedNames.
* <li>If a name in this has no name of the same type in other, then
* the result contains the name in this. No name of a given type
* means the name type is completely permitted.
* <li>If a name in other has no name of the same type in this, then
* the result contains the name in other. This means that
* the name is now constrained in some way, whereas before it was
* completely permitted.
* <ul>
*
* @param other GeneralSubtrees to be intersected with this
* @returns GeneralSubtrees to be merged with excluded; these are
* empty-valued name types corresponding to entries that were
* of the same type but did not share the same subtree between
* this and other. Returns null if no such.
*/
public GeneralSubtrees intersect(GeneralSubtrees other) {
if (other == null) {
throw new NullPointerException("other GeneralSubtrees must not be null");
}
GeneralSubtrees newThis = new GeneralSubtrees();
GeneralSubtrees newExcluded = null;
// Step 1: If this is empty, just add everything in other to this and
// return no new excluded entries
if (size() == 0) {
union(other);
return null;
}
// Step 2: For ease of checking the subtrees, minimize them by
// constructing versions that contain only the widest instance of
// each type
this.minimize();
other.minimize();
// Step 3: Check each entry in this to see whether we keep it or
// remove it, and whether we add anything to newExcluded or newThis.
// We keep an entry in this unless it is narrowed by all entries in
// other. We add an entry to newExcluded if there is at least one
// entry of the same nameType in other, but this entry does
// not share the same subtree with any of the entries in other.
// We add an entry from other to newThis if there is no name of the
// same type in this.
for (int i = 0; i < size(); i++) {
GeneralNameInterface thisEntry = getGeneralNameInterface(i);
boolean removeThisEntry = false;
// Step 3a: If the widest name of this type in other narrows
// thisEntry, remove thisEntry and add widest other to newThis.
// Simultaneously, check for situation where there is a name of
// this type in other, but no name in other matches, narrows,
// or widens thisEntry.
boolean sameType = false;
for (int j = 0; j < other.size(); j++) {
GeneralSubtree otherEntryGS = other.get(j);
GeneralNameInterface otherEntry =
getGeneralNameInterface(otherEntryGS);
switch (thisEntry.constrains(otherEntry)) {
case NAME_NARROWS:
remove(i);
i--;
newThis.add(otherEntryGS);
sameType = false;
break;
case NAME_SAME_TYPE:
sameType = true;
continue;
case NAME_MATCH:
case NAME_WIDENS:
sameType = false;
break;
case NAME_DIFF_TYPE:
default:
continue;
}
break;
}
// Step 3b: If sameType is still true, we have the situation
// where there was a name of the same type as thisEntry in
// other, but no name in other widened, matched, or narrowed
// thisEntry.
if (sameType) {
// Step 3b.1: See if there are any entries in this and other
// with this type that match, widen, or narrow each other.
// If not, then we need to add a "widest subtree" of this
// type to excluded.
boolean intersection = false;
for (int j = 0; j < size(); j++) {
GeneralNameInterface thisAltEntry = getGeneralNameInterface(j);
if (thisAltEntry.getType() == thisEntry.getType()) {
for (int k = 0; k < other.size(); k++) {
GeneralNameInterface othAltEntry =
other.getGeneralNameInterface(k);
int constraintType =
thisAltEntry.constrains(othAltEntry);
if (constraintType == NAME_MATCH ||
constraintType == NAME_WIDENS ||
constraintType == NAME_NARROWS) {
intersection = true;
break;
}
}
}
}
if (intersection == false) {
if (newExcluded == null) {
newExcluded = new GeneralSubtrees();
}
GeneralSubtree widestSubtree =
createWidestSubtree(thisEntry);
if (!newExcluded.contains(widestSubtree)) {
newExcluded.add(widestSubtree);
}
}
// Step 3b.2: Remove thisEntry from this
remove(i);
i--;
}
}
// Step 4: Add all entries in newThis to this
if (newThis.size() > 0) {
union(newThis);
}
// Step 5: Add all entries in other that do not have any entry of the
// same type in this to this
for (int i = 0; i < other.size(); i++) {
GeneralSubtree otherEntryGS = other.get(i);
GeneralNameInterface otherEntry = getGeneralNameInterface(otherEntryGS);
boolean diffType = false;
for (int j = 0; j < size(); j++) {
GeneralNameInterface thisEntry = getGeneralNameInterface(j);
switch (thisEntry.constrains(otherEntry)) {
case NAME_DIFF_TYPE:
diffType = true;
// continue to see if we find something later of the
// same type
continue;
case NAME_NARROWS:
case NAME_SAME_TYPE:
case NAME_MATCH:
case NAME_WIDENS:
diffType = false; // we found an entry of the same type
// break because we know we won't be adding it to
// this now
break;
default:
continue;
}
break;
}
if (diffType) {
add(otherEntryGS);
}
}
// Step 6: Return the newExcluded GeneralSubtrees
return newExcluded;
}
/**
* construct union of this GeneralSubtrees with other.
*
* @param other GeneralSubtrees to be united with this
*/
public void union(GeneralSubtrees other) {
if (other != null) {
for (int i = 0, n = other.size(); i < n; i++) {
add(other.get(i));
}
// Minimize this
minimize();
}
}
/**
* reduce this GeneralSubtrees by contents of another. This function
* is used in merging excluded NameConstraints with permitted NameConstraints
* to obtain a minimal form of permitted NameConstraints. It is an
* optimization, and does not affect correctness of the results.
*
* @param excluded GeneralSubtrees
*/
public void reduce(GeneralSubtrees excluded) {
if (excluded == null) {
return;
}
for (int i = 0, n = excluded.size(); i < n; i++) {
GeneralNameInterface excludedName = excluded.getGeneralNameInterface(i);
for (int j = 0; j < size(); j++) {
GeneralNameInterface permitted = getGeneralNameInterface(j);
switch (excludedName.constrains(permitted)) {
case GeneralNameInterface.NAME_DIFF_TYPE:
break;
case GeneralNameInterface.NAME_MATCH:
remove(j);
j--;
break;
case GeneralNameInterface.NAME_NARROWS:
/* permitted narrows excluded */
remove(j);
j--;
break;
case GeneralNameInterface.NAME_WIDENS:
/* permitted widens excluded */
break;
case GeneralNameInterface.NAME_SAME_TYPE:
break;
}
} /* end of this pass of permitted */
} /* end of pass of excluded */
}
}

View File

@@ -0,0 +1,491 @@
/*
* Copyright (c) 1997, 2002, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.lang.Integer;
import java.net.InetAddress;
import java.util.Arrays;
import sun.misc.HexDumpEncoder;
import sun.security.util.BitArray;
import sun.security.util.DerOutputStream;
import sun.security.util.DerValue;
/**
* This class implements the IPAddressName as required by the GeneralNames
* ASN.1 object. Both IPv4 and IPv6 addresses are supported using the
* formats specified in IETF PKIX RFC2459.
* <p>
* [RFC2459 4.2.1.7 Subject Alternative Name]
* When the subjectAltName extension contains a iPAddress, the address
* MUST be stored in the octet string in "network byte order," as
* specified in RFC 791. The least significant bit (LSB) of
* each octet is the LSB of the corresponding byte in the network
* address. For IP Version 4, as specified in RFC 791, the octet string
* MUST contain exactly four octets. For IP Version 6, as specified in
* RFC 1883, the octet string MUST contain exactly sixteen octets.
* <p>
* [RFC2459 4.2.1.11 Name Constraints]
* The syntax of iPAddress MUST be as described in section 4.2.1.7 with
* the following additions specifically for Name Constraints. For IPv4
* addresses, the ipAddress field of generalName MUST contain eight (8)
* octets, encoded in the style of RFC 1519 (CIDR) to represent an
* address range.[RFC 1519] For IPv6 addresses, the ipAddress field
* MUST contain 32 octets similarly encoded. For example, a name
* constraint for "class C" subnet 10.9.8.0 shall be represented as the
* octets 0A 09 08 00 FF FF FF 00, representing the CIDR notation
* 10.9.8.0/255.255.255.0.
* <p>
* @see GeneralName
* @see GeneralNameInterface
* @see GeneralNames
*
*
* @author Amit Kapoor
* @author Hemma Prafullchandra
*/
public class IPAddressName implements GeneralNameInterface {
private byte[] address;
private boolean isIPv4;
private String name;
/**
* Create the IPAddressName object from the passed encoded Der value.
*
* @params derValue the encoded DER IPAddressName.
* @exception IOException on error.
*/
public IPAddressName(DerValue derValue) throws IOException {
this(derValue.getOctetString());
}
/**
* Create the IPAddressName object with the specified octets.
*
* @params address the IP address
* @throws IOException if address is not a valid IPv4 or IPv6 address
*/
public IPAddressName(byte[] address) throws IOException {
/*
* A valid address must consist of 4 bytes of address and
* optional 4 bytes of 4 bytes of mask, or 16 bytes of address
* and optional 16 bytes of mask.
*/
if (address.length == 4 || address.length == 8) {
isIPv4 = true;
} else if (address.length == 16 || address.length == 32) {
isIPv4 = false;
} else {
throw new IOException("Invalid IPAddressName");
}
this.address = address;
}
/**
* Create an IPAddressName from a String.
* [IETF RFC1338 Supernetting & IETF RFC1519 Classless Inter-Domain
* Routing (CIDR)] For IPv4 addresses, the forms are
* "b1.b2.b3.b4" or "b1.b2.b3.b4/m1.m2.m3.m4", where b1 - b4 are decimal
* byte values 0-255 and m1 - m4 are decimal mask values
* 0 - 255.
* <p>
* [IETF RFC2373 IP Version 6 Addressing Architecture]
* For IPv6 addresses, the forms are "a1:a2:...:a8" or "a1:a2:...:a8/n",
* where a1-a8 are hexadecimal values representing the eight 16-bit pieces
* of the address. If /n is used, n is a decimal number indicating how many
* of the leftmost contiguous bits of the address comprise the prefix for
* this subnet. Internally, a mask value is created using the prefix length.
* <p>
* @param name String form of IPAddressName
* @throws IOException if name can not be converted to a valid IPv4 or IPv6
* address
*/
public IPAddressName(String name) throws IOException {
if (name == null || name.length() == 0) {
throw new IOException("IPAddress cannot be null or empty");
}
if (name.charAt(name.length() - 1) == '/') {
throw new IOException("Invalid IPAddress: " + name);
}
if (name.indexOf(':') >= 0) {
// name is IPv6: uses colons as value separators
// Parse name into byte-value address components and optional
// prefix
parseIPv6(name);
isIPv4 = false;
} else if (name.indexOf('.') >= 0) {
//name is IPv4: uses dots as value separators
parseIPv4(name);
isIPv4 = true;
} else {
throw new IOException("Invalid IPAddress: " + name);
}
}
/**
* Parse an IPv4 address.
*
* @param name IPv4 address with optional mask values
* @throws IOException on error
*/
private void parseIPv4(String name) throws IOException {
// Parse name into byte-value address components
int slashNdx = name.indexOf('/');
if (slashNdx == -1) {
address = InetAddress.getByName(name).getAddress();
} else {
address = new byte[8];
// parse mask
byte[] mask = InetAddress.getByName
(name.substring(slashNdx+1)).getAddress();
// parse base address
byte[] host = InetAddress.getByName
(name.substring(0, slashNdx)).getAddress();
System.arraycopy(host, 0, address, 0, 4);
System.arraycopy(mask, 0, address, 4, 4);
}
}
/**
* Parse an IPv6 address.
*
* @param name String IPv6 address with optional /<prefix length>
* If /<prefix length> is present, address[] array will
* be 32 bytes long, otherwise 16.
* @throws IOException on error
*/
private final static int MASKSIZE = 16;
private void parseIPv6(String name) throws IOException {
int slashNdx = name.indexOf('/');
if (slashNdx == -1) {
address = InetAddress.getByName(name).getAddress();
} else {
address = new byte[32];
byte[] base = InetAddress.getByName
(name.substring(0, slashNdx)).getAddress();
System.arraycopy(base, 0, address, 0, 16);
// append a mask corresponding to the num of prefix bits specified
int prefixLen = Integer.parseInt(name.substring(slashNdx+1));
if (prefixLen < 0 || prefixLen > 128) {
throw new IOException("IPv6Address prefix length (" +
prefixLen + ") in out of valid range [0,128]");
}
// create new bit array initialized to zeros
BitArray bitArray = new BitArray(MASKSIZE * 8);
// set all most significant bits up to prefix length
for (int i = 0; i < prefixLen; i++)
bitArray.set(i, true);
byte[] maskArray = bitArray.toByteArray();
// copy mask bytes into mask portion of address
for (int i = 0; i < MASKSIZE; i++)
address[MASKSIZE+i] = maskArray[i];
}
}
/**
* Return the type of the GeneralName.
*/
public int getType() {
return NAME_IP;
}
/**
* Encode the IPAddress name into the DerOutputStream.
*
* @params out the DER stream to encode the IPAddressName to.
* @exception IOException on encoding errors.
*/
public void encode(DerOutputStream out) throws IOException {
out.putOctetString(address);
}
/**
* Return a printable string of IPaddress
*/
public String toString() {
try {
return "IPAddress: " + getName();
} catch (IOException ioe) {
// dump out hex rep for debugging purposes
HexDumpEncoder enc = new HexDumpEncoder();
return "IPAddress: " + enc.encodeBuffer(address);
}
}
/**
* Return a standard String representation of IPAddress.
* See IPAddressName(String) for the formats used for IPv4
* and IPv6 addresses.
*
* @throws IOException if the IPAddress cannot be converted to a String
*/
public String getName() throws IOException {
if (name != null)
return name;
if (isIPv4) {
//IPv4 address or subdomain
byte[] host = new byte[4];
System.arraycopy(address, 0, host, 0, 4);
name = InetAddress.getByAddress(host).getHostAddress();
if (address.length == 8) {
byte[] mask = new byte[4];
System.arraycopy(address, 4, mask, 0, 4);
name = name + "/" +
InetAddress.getByAddress(mask).getHostAddress();
}
} else {
//IPv6 address or subdomain
byte[] host = new byte[16];
System.arraycopy(address, 0, host, 0, 16);
name = InetAddress.getByAddress(host).getHostAddress();
if (address.length == 32) {
// IPv6 subdomain: display prefix length
// copy subdomain into new array and convert to BitArray
byte[] maskBytes = new byte[16];
for (int i=16; i < 32; i++)
maskBytes[i-16] = address[i];
BitArray ba = new BitArray(16*8, maskBytes);
// Find first zero bit
int i=0;
for (; i < 16*8; i++) {
if (!ba.get(i))
break;
}
name = name + "/" + i;
// Verify remaining bits 0
for (; i < 16*8; i++) {
if (ba.get(i)) {
throw new IOException("Invalid IPv6 subdomain - set " +
"bit " + i + " not contiguous");
}
}
}
}
return name;
}
/**
* Returns this IPAddress name as a byte array.
*/
public byte[] getBytes() {
return address.clone();
}
/**
* Compares this name with another, for equality.
*
* @return true iff the names are identical.
*/
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!(obj instanceof IPAddressName))
return false;
IPAddressName otherName = (IPAddressName)obj;
byte[] other = otherName.address;
if (other.length != address.length)
return false;
if (address.length == 8 || address.length == 32) {
// Two subnet addresses
// Mask each and compare masked values
int maskLen = address.length/2;
for (int i=0; i < maskLen; i++) {
byte maskedThis = (byte)(address[i] & address[i+maskLen]);
byte maskedOther = (byte)(other[i] & other[i+maskLen]);
if (maskedThis != maskedOther) {
return false;
}
}
// Now compare masks
for (int i=maskLen; i < address.length; i++)
if (address[i] != other[i])
return false;
return true;
} else {
// Two IPv4 host addresses or two IPv6 host addresses
// Compare bytes
return Arrays.equals(other, address);
}
}
/**
* Returns the hash code value for this object.
*
* @return a hash code value for this object.
*/
public int hashCode() {
int retval = 0;
for (int i=0; i<address.length; i++)
retval += address[i] * i;
return retval;
}
/**
* Return type of constraint inputName places on this name:<ul>
* <li>NAME_DIFF_TYPE = -1: input name is different type from name
* (i.e. does not constrain).
* <li>NAME_MATCH = 0: input name matches name.
* <li>NAME_NARROWS = 1: input name narrows name (is lower in the naming
* subtree)
* <li>NAME_WIDENS = 2: input name widens name (is higher in the naming
* subtree)
* <li>NAME_SAME_TYPE = 3: input name does not match or narrow name, but
* is same type.
* </ul>. These results are used in checking NameConstraints during
* certification path verification.
* <p>
* [RFC2459] The syntax of iPAddress MUST be as described in section
* 4.2.1.7 with the following additions specifically for Name Constraints.
* For IPv4 addresses, the ipAddress field of generalName MUST contain
* eight (8) octets, encoded in the style of RFC 1519 (CIDR) to represent an
* address range.[RFC 1519] For IPv6 addresses, the ipAddress field
* MUST contain 32 octets similarly encoded. For example, a name
* constraint for "class C" subnet 10.9.8.0 shall be represented as the
* octets 0A 09 08 00 FF FF FF 00, representing the CIDR notation
* 10.9.8.0/255.255.255.0.
* <p>
* @param inputName to be checked for being constrained
* @returns constraint type above
* @throws UnsupportedOperationException if name is not exact match, but
* narrowing and widening are not supported for this name type.
*/
public int constrains(GeneralNameInterface inputName)
throws UnsupportedOperationException {
int constraintType;
if (inputName == null)
constraintType = NAME_DIFF_TYPE;
else if (inputName.getType() != NAME_IP)
constraintType = NAME_DIFF_TYPE;
else if (((IPAddressName)inputName).equals(this))
constraintType = NAME_MATCH;
else {
IPAddressName otherName = (IPAddressName)inputName;
byte[] otherAddress = otherName.address;
if (otherAddress.length == 4 && address.length == 4)
// Two host addresses
constraintType = NAME_SAME_TYPE;
else if ((otherAddress.length == 8 && address.length == 8) ||
(otherAddress.length == 32 && address.length == 32)) {
// Two subnet addresses
// See if one address fully encloses the other address
boolean otherSubsetOfThis = true;
boolean thisSubsetOfOther = true;
boolean thisEmpty = false;
boolean otherEmpty = false;
int maskOffset = address.length/2;
for (int i=0; i < maskOffset; i++) {
if ((byte)(address[i] & address[i+maskOffset]) != address[i])
thisEmpty=true;
if ((byte)(otherAddress[i] & otherAddress[i+maskOffset]) != otherAddress[i])
otherEmpty=true;
if (!(((byte)(address[i+maskOffset] & otherAddress[i+maskOffset]) == address[i+maskOffset]) &&
((byte)(address[i] & address[i+maskOffset]) == (byte)(otherAddress[i] & address[i+maskOffset])))) {
otherSubsetOfThis = false;
}
if (!(((byte)(otherAddress[i+maskOffset] & address[i+maskOffset]) == otherAddress[i+maskOffset]) &&
((byte)(otherAddress[i] & otherAddress[i+maskOffset]) == (byte)(address[i] & otherAddress[i+maskOffset])))) {
thisSubsetOfOther = false;
}
}
if (thisEmpty || otherEmpty) {
if (thisEmpty && otherEmpty)
constraintType = NAME_MATCH;
else if (thisEmpty)
constraintType = NAME_WIDENS;
else
constraintType = NAME_NARROWS;
} else if (otherSubsetOfThis)
constraintType = NAME_NARROWS;
else if (thisSubsetOfOther)
constraintType = NAME_WIDENS;
else
constraintType = NAME_SAME_TYPE;
} else if (otherAddress.length == 8 || otherAddress.length == 32) {
//Other is a subnet, this is a host address
int i = 0;
int maskOffset = otherAddress.length/2;
for (; i < maskOffset; i++) {
// Mask this address by other address mask and compare to other address
// If all match, then this address is in other address subnet
if ((address[i] & otherAddress[i+maskOffset]) != otherAddress[i])
break;
}
if (i == maskOffset)
constraintType = NAME_WIDENS;
else
constraintType = NAME_SAME_TYPE;
} else if (address.length == 8 || address.length == 32) {
//This is a subnet, other is a host address
int i = 0;
int maskOffset = address.length/2;
for (; i < maskOffset; i++) {
// Mask other address by this address mask and compare to this address
if ((otherAddress[i] & address[i+maskOffset]) != address[i])
break;
}
if (i == maskOffset)
constraintType = NAME_NARROWS;
else
constraintType = NAME_SAME_TYPE;
} else {
constraintType = NAME_SAME_TYPE;
}
}
return constraintType;
}
/**
* Return subtree depth of this name for purposes of determining
* NameConstraints minimum and maximum bounds and for calculating
* path lengths in name subtrees.
*
* @returns distance of name from root
* @throws UnsupportedOperationException if not supported for this name type
*/
public int subtreeDepth() throws UnsupportedOperationException {
throw new UnsupportedOperationException
("subtreeDepth() not defined for IPAddressName");
}
}

View File

@@ -0,0 +1,263 @@
/*
* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Enumeration;
import sun.security.util.Debug;
import sun.security.util.DerOutputStream;
import sun.security.util.DerValue;
import sun.security.util.ObjectIdentifier;
/**
* This class represents the Inhibit Any-Policy Extension.
*
* <p>The inhibit any-policy extension can be used in certificates issued
* to CAs. The inhibit any-policy indicates that the special any-policy
* OID, with the value {2 5 29 32 0}, is not considered an explicit
* match for other certificate policies. The value indicates the number
* of additional certificates that may appear in the path before any-
* policy is no longer permitted. For example, a value of one indicates
* that any-policy may be processed in certificates issued by the sub-
* ject of this certificate, but not in additional certificates in the
* path.
* <p>
* This extension MUST be critical.
* <p>
* The ASN.1 syntax for this extension is:
* <code><pre>
* id-ce-inhibitAnyPolicy OBJECT IDENTIFIER ::= { id-ce 54 }
*
* InhibitAnyPolicy ::= SkipCerts
*
* SkipCerts ::= INTEGER (0..MAX)
* </pre></code>
* @author Anne Anderson
* @see CertAttrSet
* @see Extension
*/
public class InhibitAnyPolicyExtension extends Extension
implements CertAttrSet<String> {
private static final Debug debug = Debug.getInstance("certpath");
/**
* Identifier for this attribute, to be used with the
* get, set, delete methods of Certificate, x509 type.
*/
public static final String IDENT = "x509.info.extensions.InhibitAnyPolicy";
/**
* Object identifier for "any-policy"
*/
public static ObjectIdentifier AnyPolicy_Id;
static {
try {
AnyPolicy_Id = new ObjectIdentifier("2.5.29.32.0");
} catch (IOException ioe) {
// Should not happen
}
}
/**
* Attribute names.
*/
public static final String NAME = "InhibitAnyPolicy";
public static final String SKIP_CERTS = "skip_certs";
// Private data members
private int skipCerts = Integer.MAX_VALUE;
// Encode this extension value
private void encodeThis() throws IOException {
DerOutputStream out = new DerOutputStream();
out.putInteger(skipCerts);
this.extensionValue = out.toByteArray();
}
/**
* Default constructor for this object.
*
* @param skipCerts specifies the depth of the certification path.
* Use value of -1 to request unlimited depth.
*/
public InhibitAnyPolicyExtension(int skipCerts) throws IOException {
if (skipCerts < -1)
throw new IOException("Invalid value for skipCerts");
if (skipCerts == -1)
this.skipCerts = Integer.MAX_VALUE;
else
this.skipCerts = skipCerts;
this.extensionId = PKIXExtensions.InhibitAnyPolicy_Id;
critical = true;
encodeThis();
}
/**
* Create the extension from the passed DER encoded value of the same.
*
* @param critical criticality flag to use. Must be true for this
* extension.
* @param value a byte array holding the DER-encoded extension value.
* @exception ClassCastException if value is not an array of bytes
* @exception IOException on error.
*/
public InhibitAnyPolicyExtension(Boolean critical, Object value)
throws IOException {
this.extensionId = PKIXExtensions.InhibitAnyPolicy_Id;
if (!critical.booleanValue())
throw new IOException("Criticality cannot be false for " +
"InhibitAnyPolicy");
this.critical = critical.booleanValue();
this.extensionValue = (byte[]) value;
DerValue val = new DerValue(this.extensionValue);
if (val.tag != DerValue.tag_Integer)
throw new IOException("Invalid encoding of InhibitAnyPolicy: "
+ "data not integer");
if (val.data == null)
throw new IOException("Invalid encoding of InhibitAnyPolicy: "
+ "null data");
int skipCertsValue = val.getInteger();
if (skipCertsValue < -1)
throw new IOException("Invalid value for skipCerts");
if (skipCertsValue == -1) {
this.skipCerts = Integer.MAX_VALUE;
} else {
this.skipCerts = skipCertsValue;
}
}
/**
* Return user readable form of extension.
*/
public String toString() {
String s = super.toString() + "InhibitAnyPolicy: " + skipCerts + "\n";
return s;
}
/**
* Encode this extension value to the output stream.
*
* @param out the DerOutputStream to encode the extension to.
*/
public void encode(OutputStream out) throws IOException {
DerOutputStream tmp = new DerOutputStream();
if (extensionValue == null) {
this.extensionId = PKIXExtensions.InhibitAnyPolicy_Id;
critical = true;
encodeThis();
}
super.encode(tmp);
out.write(tmp.toByteArray());
}
/**
* Set the attribute value.
*
* @param name name of attribute to set. Must be SKIP_CERTS.
* @param obj value to which attribute is to be set. Must be Integer
* type.
* @throws IOException on error
*/
public void set(String name, Object obj) throws IOException {
if (name.equalsIgnoreCase(SKIP_CERTS)) {
if (!(obj instanceof Integer))
throw new IOException("Attribute value should be of type Integer.");
int skipCertsValue = ((Integer)obj).intValue();
if (skipCertsValue < -1)
throw new IOException("Invalid value for skipCerts");
if (skipCertsValue == -1) {
skipCerts = Integer.MAX_VALUE;
} else {
skipCerts = skipCertsValue;
}
} else
throw new IOException("Attribute name not recognized by " +
"CertAttrSet:InhibitAnyPolicy.");
encodeThis();
}
/**
* Get the attribute value.
*
* @param name name of attribute to get. Must be SKIP_CERTS.
* @returns value of the attribute. In this case it will be of type
* Integer.
* @throws IOException on error
*/
public Integer get(String name) throws IOException {
if (name.equalsIgnoreCase(SKIP_CERTS))
return (new Integer(skipCerts));
else
throw new IOException("Attribute name not recognized by " +
"CertAttrSet:InhibitAnyPolicy.");
}
/**
* Delete the attribute value.
*
* @param name name of attribute to delete. Must be SKIP_CERTS.
* @throws IOException on error. In this case, IOException will always be
* thrown, because the only attribute, SKIP_CERTS, is
* required.
*/
public void delete(String name) throws IOException {
if (name.equalsIgnoreCase(SKIP_CERTS))
throw new IOException("Attribute " + SKIP_CERTS +
" may not be deleted.");
else
throw new IOException("Attribute name not recognized by " +
"CertAttrSet:InhibitAnyPolicy.");
}
/**
* Return an enumeration of names of attributes existing within this
* attribute.
*
* @returns enumeration of elements
*/
public Enumeration<String> getElements() {
AttributeNameEnumeration elements = new AttributeNameEnumeration();
elements.addElement(SKIP_CERTS);
return (elements.elements());
}
/**
* Return the name of this attribute.
*
* @returns name of attribute.
*/
public String getName() {
return (NAME);
}
}

View File

@@ -0,0 +1,219 @@
/*
* Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Date;
import java.util.Enumeration;
import sun.security.util.*;
/**
* From RFC 5280:
* <p>
* The invalidity date is a non-critical CRL entry extension that
* provides the date on which it is known or suspected that the private
* key was compromised or that the certificate otherwise became invalid.
* This date may be earlier than the revocation date in the CRL entry,
* which is the date at which the CA processed the revocation. When a
* revocation is first posted by a CRL issuer in a CRL, the invalidity
* date may precede the date of issue of earlier CRLs, but the
* revocation date SHOULD NOT precede the date of issue of earlier CRLs.
* Whenever this information is available, CRL issuers are strongly
* encouraged to share it with CRL users.
* <p>
* The GeneralizedTime values included in this field MUST be expressed
* in Greenwich Mean Time (Zulu), and MUST be specified and interpreted
* as defined in section 4.1.2.5.2.
* <pre>
* id-ce-invalidityDate OBJECT IDENTIFIER ::= { id-ce 24 }
*
* invalidityDate ::= GeneralizedTime
* </pre>
*
* @author Sean Mullan
*/
public class InvalidityDateExtension extends Extension
implements CertAttrSet<String> {
/**
* Attribute name and Reason codes
*/
public static final String NAME = "InvalidityDate";
public static final String DATE = "date";
private Date date;
private void encodeThis() throws IOException {
if (date == null) {
this.extensionValue = null;
return;
}
DerOutputStream dos = new DerOutputStream();
dos.putGeneralizedTime(date);
this.extensionValue = dos.toByteArray();
}
/**
* Create a InvalidityDateExtension with the passed in date.
* Criticality automatically set to false.
*
* @param date the invalidity date
*/
public InvalidityDateExtension(Date date) throws IOException {
this(false, date);
}
/**
* Create a InvalidityDateExtension with the passed in date.
*
* @param critical true if the extension is to be treated as critical.
* @param date the invalidity date
*/
public InvalidityDateExtension(boolean critical, Date date)
throws IOException {
this.extensionId = PKIXExtensions.InvalidityDate_Id;
this.critical = critical;
this.date = date;
encodeThis();
}
/**
* Create the extension from the passed DER encoded value of the same.
*
* @param critical true if the extension is to be treated as critical.
* @param value an array of DER encoded bytes of the actual value.
* @exception ClassCastException if value is not an array of bytes
* @exception IOException on error.
*/
public InvalidityDateExtension(Boolean critical, Object value)
throws IOException {
this.extensionId = PKIXExtensions.InvalidityDate_Id;
this.critical = critical.booleanValue();
this.extensionValue = (byte[]) value;
DerValue val = new DerValue(this.extensionValue);
this.date = val.getGeneralizedTime();
}
/**
* Set the attribute value.
*/
public void set(String name, Object obj) throws IOException {
if (!(obj instanceof Date)) {
throw new IOException("Attribute must be of type Date.");
}
if (name.equalsIgnoreCase(DATE)) {
date = (Date) obj;
} else {
throw new IOException
("Name not supported by InvalidityDateExtension");
}
encodeThis();
}
/**
* Get the attribute value.
*/
public Date get(String name) throws IOException {
if (name.equalsIgnoreCase(DATE)) {
if (date == null) {
return null;
} else {
return (new Date(date.getTime())); // clone
}
} else {
throw new IOException
("Name not supported by InvalidityDateExtension");
}
}
/**
* Delete the attribute value.
*/
public void delete(String name) throws IOException {
if (name.equalsIgnoreCase(DATE)) {
date = null;
} else {
throw new IOException
("Name not supported by InvalidityDateExtension");
}
encodeThis();
}
/**
* Returns a printable representation of the Invalidity Date.
*/
public String toString() {
return super.toString() + " Invalidity Date: " + String.valueOf(date);
}
/**
* Write the extension to the DerOutputStream.
*
* @param out the DerOutputStream to write the extension to
* @exception IOException on encoding errors
*/
public void encode(OutputStream out) throws IOException {
DerOutputStream tmp = new DerOutputStream();
if (this.extensionValue == null) {
this.extensionId = PKIXExtensions.InvalidityDate_Id;
this.critical = false;
encodeThis();
}
super.encode(tmp);
out.write(tmp.toByteArray());
}
/**
* Return an enumeration of names of attributes existing within this
* attribute.
*/
public Enumeration<String> getElements() {
AttributeNameEnumeration elements = new AttributeNameEnumeration();
elements.addElement(DATE);
return elements.elements();
}
/**
* Return the name of this attribute.
*/
public String getName() {
return NAME;
}
public static InvalidityDateExtension toImpl(java.security.cert.Extension ext)
throws IOException {
if (ext instanceof InvalidityDateExtension) {
return (InvalidityDateExtension) ext;
} else {
return new InvalidityDateExtension
(Boolean.valueOf(ext.isCritical()), ext.getValue());
}
}
}

View File

@@ -0,0 +1,232 @@
/*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Enumeration;
import sun.security.util.*;
/**
* This represents the Issuer Alternative Name Extension.
*
* This extension, if present, allows the issuer to specify multiple
* alternative names.
*
* <p>Extensions are represented as a sequence of the extension identifier
* (Object Identifier), a boolean flag stating whether the extension is to
* be treated as being critical and the extension value itself (this is again
* a DER encoding of the extension value).
*
* @author Amit Kapoor
* @author Hemma Prafullchandra
* @see Extension
* @see CertAttrSet
*/
public class IssuerAlternativeNameExtension
extends Extension implements CertAttrSet<String> {
/**
* Identifier for this attribute, to be used with the
* get, set, delete methods of Certificate, x509 type.
*/
public static final String IDENT =
"x509.info.extensions.IssuerAlternativeName";
/**
* Attribute names.
*/
public static final String NAME = "IssuerAlternativeName";
public static final String ISSUER_NAME = "issuer_name";
// private data members
GeneralNames names = null;
// Encode this extension
private void encodeThis() throws IOException {
if (names == null || names.isEmpty()) {
this.extensionValue = null;
return;
}
DerOutputStream os = new DerOutputStream();
names.encode(os);
this.extensionValue = os.toByteArray();
}
/**
* Create a IssuerAlternativeNameExtension with the passed GeneralNames.
*
* @param names the GeneralNames for the issuer.
* @exception IOException on error.
*/
public IssuerAlternativeNameExtension(GeneralNames names)
throws IOException {
this.names = names;
this.extensionId = PKIXExtensions.IssuerAlternativeName_Id;
this.critical = false;
encodeThis();
}
/**
* Create a IssuerAlternativeNameExtension with the passed criticality
* and GeneralNames.
*
* @param critical true if the extension is to be treated as critical.
* @param names the GeneralNames for the issuer.
* @exception IOException on error.
*/
public IssuerAlternativeNameExtension(Boolean critical, GeneralNames names)
throws IOException {
this.names = names;
this.extensionId = PKIXExtensions.IssuerAlternativeName_Id;
this.critical = critical.booleanValue();
encodeThis();
}
/**
* Create a default IssuerAlternativeNameExtension.
*/
public IssuerAlternativeNameExtension() {
extensionId = PKIXExtensions.IssuerAlternativeName_Id;
critical = false;
names = new GeneralNames();
}
/**
* Create the extension from the passed DER encoded value.
*
* @param critical true if the extension is to be treated as critical.
* @param value an array of DER encoded bytes of the actual value.
* @exception ClassCastException if value is not an array of bytes
* @exception IOException on error.
*/
public IssuerAlternativeNameExtension(Boolean critical, Object value)
throws IOException {
this.extensionId = PKIXExtensions.IssuerAlternativeName_Id;
this.critical = critical.booleanValue();
this.extensionValue = (byte[]) value;
DerValue val = new DerValue(this.extensionValue);
if (val.data == null) {
names = new GeneralNames();
return;
}
names = new GeneralNames(val);
}
/**
* Returns a printable representation of the IssuerAlternativeName.
*/
public String toString() {
String result = super.toString() + "IssuerAlternativeName [\n";
if(names == null) {
result += " null\n";
} else {
for(GeneralName name: names.names()) {
result += " "+name+"\n";
}
}
result += "]\n";
return result;
}
/**
* Write the extension to the OutputStream.
*
* @param out the OutputStream to write the extension to.
* @exception IOException on encoding error.
*/
public void encode(OutputStream out) throws IOException {
DerOutputStream tmp = new DerOutputStream();
if (extensionValue == null) {
extensionId = PKIXExtensions.IssuerAlternativeName_Id;
critical = false;
encodeThis();
}
super.encode(tmp);
out.write(tmp.toByteArray());
}
/**
* Set the attribute value.
*/
public void set(String name, Object obj) throws IOException {
if (name.equalsIgnoreCase(ISSUER_NAME)) {
if (!(obj instanceof GeneralNames)) {
throw new IOException("Attribute value should be of" +
" type GeneralNames.");
}
names = (GeneralNames)obj;
} else {
throw new IOException("Attribute name not recognized by " +
"CertAttrSet:IssuerAlternativeName.");
}
encodeThis();
}
/**
* Get the attribute value.
*/
public GeneralNames get(String name) throws IOException {
if (name.equalsIgnoreCase(ISSUER_NAME)) {
return (names);
} else {
throw new IOException("Attribute name not recognized by " +
"CertAttrSet:IssuerAlternativeName.");
}
}
/**
* Delete the attribute value.
*/
public void delete(String name) throws IOException {
if (name.equalsIgnoreCase(ISSUER_NAME)) {
names = null;
} else {
throw new IOException("Attribute name not recognized by " +
"CertAttrSet:IssuerAlternativeName.");
}
encodeThis();
}
/**
* Return an enumeration of names of attributes existing within this
* attribute.
*/
public Enumeration<String> getElements() {
AttributeNameEnumeration elements = new AttributeNameEnumeration();
elements.addElement(ISSUER_NAME);
return (elements.elements());
}
/**
* Return the name of this attribute.
*/
public String getName() {
return (NAME);
}
}

View File

@@ -0,0 +1,477 @@
/*
* Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.io.OutputStream;
import java.util.*;
import sun.security.util.DerInputStream;
import sun.security.util.DerOutputStream;
import sun.security.util.DerValue;
/**
* Represents the CRL Issuing Distribution Point Extension (OID = 2.5.29.28).
*
* <p>
* The issuing distribution point is a critical CRL extension that
* identifies the CRL distribution point and scope for a particular CRL,
* and it indicates whether the CRL covers revocation for end entity
* certificates only, CA certificates only, attribute certificates only,
* or a limited set of reason codes.
*
* <p>
* The extension is defined in Section 5.2.5 of
* <a href="http://tools.ietf.org/html/rfc5280">Internet X.509 PKI Certific
ate and Certificate Revocation List (CRL) Profile</a>.
*
* <p>
* Its ASN.1 definition is as follows:
* <pre>
* id-ce-issuingDistributionPoint OBJECT IDENTIFIER ::= { id-ce 28 }
*
* issuingDistributionPoint ::= SEQUENCE {
* distributionPoint [0] DistributionPointName OPTIONAL,
* onlyContainsUserCerts [1] BOOLEAN DEFAULT FALSE,
* onlyContainsCACerts [2] BOOLEAN DEFAULT FALSE,
* onlySomeReasons [3] ReasonFlags OPTIONAL,
* indirectCRL [4] BOOLEAN DEFAULT FALSE,
* onlyContainsAttributeCerts [5] BOOLEAN DEFAULT FALSE }
* </pre>
*
* @see DistributionPoint
* @since 1.6
*/
public class IssuingDistributionPointExtension extends Extension
implements CertAttrSet<String> {
/**
* Identifier for this attribute, to be used with the
* get, set, delete methods of Certificate, x509 type.
*/
public static final String IDENT =
"x509.info.extensions.IssuingDistributionPoint";
/**
* Attribute names.
*/
public static final String NAME = "IssuingDistributionPoint";
public static final String POINT = "point";
public static final String REASONS = "reasons";
public static final String ONLY_USER_CERTS = "only_user_certs";
public static final String ONLY_CA_CERTS = "only_ca_certs";
public static final String ONLY_ATTRIBUTE_CERTS = "only_attribute_certs";
public static final String INDIRECT_CRL = "indirect_crl";
/*
* The distribution point name for the CRL.
*/
private DistributionPointName distributionPoint = null;
/*
* The scope settings for the CRL.
*/
private ReasonFlags revocationReasons = null;
private boolean hasOnlyUserCerts = false;
private boolean hasOnlyCACerts = false;
private boolean hasOnlyAttributeCerts = false;
private boolean isIndirectCRL = false;
/*
* ASN.1 context specific tag values
*/
private static final byte TAG_DISTRIBUTION_POINT = 0;
private static final byte TAG_ONLY_USER_CERTS = 1;
private static final byte TAG_ONLY_CA_CERTS = 2;
private static final byte TAG_ONLY_SOME_REASONS = 3;
private static final byte TAG_INDIRECT_CRL = 4;
private static final byte TAG_ONLY_ATTRIBUTE_CERTS = 5;
/**
* Creates a critical IssuingDistributionPointExtension.
*
* @param distributionPoint the name of the distribution point, or null for
* none.
* @param revocationReasons the revocation reasons associated with the
* distribution point, or null for none.
* @param hasOnlyUserCerts if <code>true</code> then scope of the CRL
* includes only user certificates.
* @param hasOnlyCACerts if <code>true</code> then scope of the CRL
* includes only CA certificates.
* @param hasOnlyAttributeCerts if <code>true</code> then scope of the CRL
* includes only attribute certificates.
* @param isIndirectCRL if <code>true</code> then the scope of the CRL
* includes certificates issued by authorities other than the CRL
* issuer. The responsible authority is indicated by a certificate
* issuer CRL entry extension.
* @throws IllegalArgumentException if more than one of
* <code>hasOnlyUserCerts</code>, <code>hasOnlyCACerts</code>,
* <code>hasOnlyAttributeCerts</code> is set to <code>true</code>.
* @throws IOException on encoding error.
*/
public IssuingDistributionPointExtension(
DistributionPointName distributionPoint, ReasonFlags revocationReasons,
boolean hasOnlyUserCerts, boolean hasOnlyCACerts,
boolean hasOnlyAttributeCerts, boolean isIndirectCRL)
throws IOException {
if ((hasOnlyUserCerts && (hasOnlyCACerts || hasOnlyAttributeCerts)) ||
(hasOnlyCACerts && (hasOnlyUserCerts || hasOnlyAttributeCerts)) ||
(hasOnlyAttributeCerts && (hasOnlyUserCerts || hasOnlyCACerts))) {
throw new IllegalArgumentException(
"Only one of hasOnlyUserCerts, hasOnlyCACerts, " +
"hasOnlyAttributeCerts may be set to true");
}
this.extensionId = PKIXExtensions.IssuingDistributionPoint_Id;
this.critical = true;
this.distributionPoint = distributionPoint;
this.revocationReasons = revocationReasons;
this.hasOnlyUserCerts = hasOnlyUserCerts;
this.hasOnlyCACerts = hasOnlyCACerts;
this.hasOnlyAttributeCerts = hasOnlyAttributeCerts;
this.isIndirectCRL = isIndirectCRL;
encodeThis();
}
/**
* Creates a critical IssuingDistributionPointExtension from its
* DER-encoding.
*
* @param critical true if the extension is to be treated as critical.
* @param value the DER-encoded value. It must be a <code>byte[]</code>.
* @exception IOException on decoding error.
*/
public IssuingDistributionPointExtension(Boolean critical, Object value)
throws IOException {
this.extensionId = PKIXExtensions.IssuingDistributionPoint_Id;
this.critical = critical.booleanValue();
if (!(value instanceof byte[])) {
throw new IOException("Illegal argument type");
}
extensionValue = (byte[])value;
DerValue val = new DerValue(extensionValue);
if (val.tag != DerValue.tag_Sequence) {
throw new IOException("Invalid encoding for " +
"IssuingDistributionPointExtension.");
}
// All the elements in issuingDistributionPoint are optional
if ((val.data == null) || (val.data.available() == 0)) {
return;
}
DerInputStream in = val.data;
while (in != null && in.available() != 0) {
DerValue opt = in.getDerValue();
if (opt.isContextSpecific(TAG_DISTRIBUTION_POINT) &&
opt.isConstructed()) {
distributionPoint =
new DistributionPointName(opt.data.getDerValue());
} else if (opt.isContextSpecific(TAG_ONLY_USER_CERTS) &&
!opt.isConstructed()) {
opt.resetTag(DerValue.tag_Boolean);
hasOnlyUserCerts = opt.getBoolean();
} else if (opt.isContextSpecific(TAG_ONLY_CA_CERTS) &&
!opt.isConstructed()) {
opt.resetTag(DerValue.tag_Boolean);
hasOnlyCACerts = opt.getBoolean();
} else if (opt.isContextSpecific(TAG_ONLY_SOME_REASONS) &&
!opt.isConstructed()) {
revocationReasons = new ReasonFlags(opt); // expects tag implicit
} else if (opt.isContextSpecific(TAG_INDIRECT_CRL) &&
!opt.isConstructed()) {
opt.resetTag(DerValue.tag_Boolean);
isIndirectCRL = opt.getBoolean();
} else if (opt.isContextSpecific(TAG_ONLY_ATTRIBUTE_CERTS) &&
!opt.isConstructed()) {
opt.resetTag(DerValue.tag_Boolean);
hasOnlyAttributeCerts = opt.getBoolean();
} else {
throw new IOException
("Invalid encoding of IssuingDistributionPoint");
}
}
}
/**
* Returns the name of this attribute.
*/
public String getName() {
return NAME;
}
/**
* Encodes the issuing distribution point extension and writes it to the
* DerOutputStream.
*
* @param out the output stream.
* @exception IOException on encoding error.
*/
public void encode(OutputStream out) throws IOException {
DerOutputStream tmp = new DerOutputStream();
if (this.extensionValue == null) {
this.extensionId = PKIXExtensions.IssuingDistributionPoint_Id;
this.critical = false;
encodeThis();
}
super.encode(tmp);
out.write(tmp.toByteArray());
}
/**
* Sets the attribute value.
*/
public void set(String name, Object obj) throws IOException {
if (name.equalsIgnoreCase(POINT)) {
if (!(obj instanceof DistributionPointName)) {
throw new IOException(
"Attribute value should be of type DistributionPointName.");
}
distributionPoint = (DistributionPointName)obj;
} else if (name.equalsIgnoreCase(REASONS)) {
if (!(obj instanceof ReasonFlags)) {
throw new IOException(
"Attribute value should be of type ReasonFlags.");
}
revocationReasons = (ReasonFlags)obj;
} else if (name.equalsIgnoreCase(INDIRECT_CRL)) {
if (!(obj instanceof Boolean)) {
throw new IOException(
"Attribute value should be of type Boolean.");
}
isIndirectCRL = ((Boolean)obj).booleanValue();
} else if (name.equalsIgnoreCase(ONLY_USER_CERTS)) {
if (!(obj instanceof Boolean)) {
throw new IOException(
"Attribute value should be of type Boolean.");
}
hasOnlyUserCerts = ((Boolean)obj).booleanValue();
} else if (name.equalsIgnoreCase(ONLY_CA_CERTS)) {
if (!(obj instanceof Boolean)) {
throw new IOException(
"Attribute value should be of type Boolean.");
}
hasOnlyCACerts = ((Boolean)obj).booleanValue();
} else if (name.equalsIgnoreCase(ONLY_ATTRIBUTE_CERTS)) {
if (!(obj instanceof Boolean)) {
throw new IOException(
"Attribute value should be of type Boolean.");
}
hasOnlyAttributeCerts = ((Boolean)obj).booleanValue();
} else {
throw new IOException("Attribute name [" + name +
"] not recognized by " +
"CertAttrSet:IssuingDistributionPointExtension.");
}
encodeThis();
}
/**
* Gets the attribute value.
*/
public Object get(String name) throws IOException {
if (name.equalsIgnoreCase(POINT)) {
return distributionPoint;
} else if (name.equalsIgnoreCase(INDIRECT_CRL)) {
return Boolean.valueOf(isIndirectCRL);
} else if (name.equalsIgnoreCase(REASONS)) {
return revocationReasons;
} else if (name.equalsIgnoreCase(ONLY_USER_CERTS)) {
return Boolean.valueOf(hasOnlyUserCerts);
} else if (name.equalsIgnoreCase(ONLY_CA_CERTS)) {
return Boolean.valueOf(hasOnlyCACerts);
} else if (name.equalsIgnoreCase(ONLY_ATTRIBUTE_CERTS)) {
return Boolean.valueOf(hasOnlyAttributeCerts);
} else {
throw new IOException("Attribute name [" + name +
"] not recognized by " +
"CertAttrSet:IssuingDistributionPointExtension.");
}
}
/**
* Deletes the attribute value.
*/
public void delete(String name) throws IOException {
if (name.equalsIgnoreCase(POINT)) {
distributionPoint = null;
} else if (name.equalsIgnoreCase(INDIRECT_CRL)) {
isIndirectCRL = false;
} else if (name.equalsIgnoreCase(REASONS)) {
revocationReasons = null;
} else if (name.equalsIgnoreCase(ONLY_USER_CERTS)) {
hasOnlyUserCerts = false;
} else if (name.equalsIgnoreCase(ONLY_CA_CERTS)) {
hasOnlyCACerts = false;
} else if (name.equalsIgnoreCase(ONLY_ATTRIBUTE_CERTS)) {
hasOnlyAttributeCerts = false;
} else {
throw new IOException("Attribute name [" + name +
"] not recognized by " +
"CertAttrSet:IssuingDistributionPointExtension.");
}
encodeThis();
}
/**
* Returns an enumeration of names of attributes existing within this
* attribute.
*/
public Enumeration<String> getElements() {
AttributeNameEnumeration elements = new AttributeNameEnumeration();
elements.addElement(POINT);
elements.addElement(REASONS);
elements.addElement(ONLY_USER_CERTS);
elements.addElement(ONLY_CA_CERTS);
elements.addElement(ONLY_ATTRIBUTE_CERTS);
elements.addElement(INDIRECT_CRL);
return elements.elements();
}
// Encodes this extension value
private void encodeThis() throws IOException {
if (distributionPoint == null &&
revocationReasons == null &&
!hasOnlyUserCerts &&
!hasOnlyCACerts &&
!hasOnlyAttributeCerts &&
!isIndirectCRL) {
this.extensionValue = null;
return;
}
DerOutputStream tagged = new DerOutputStream();
if (distributionPoint != null) {
DerOutputStream tmp = new DerOutputStream();
distributionPoint.encode(tmp);
tagged.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT, true,
TAG_DISTRIBUTION_POINT), tmp);
}
if (hasOnlyUserCerts) {
DerOutputStream tmp = new DerOutputStream();
tmp.putBoolean(hasOnlyUserCerts);
tagged.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT, false,
TAG_ONLY_USER_CERTS), tmp);
}
if (hasOnlyCACerts) {
DerOutputStream tmp = new DerOutputStream();
tmp.putBoolean(hasOnlyCACerts);
tagged.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT, false,
TAG_ONLY_CA_CERTS), tmp);
}
if (revocationReasons != null) {
DerOutputStream tmp = new DerOutputStream();
revocationReasons.encode(tmp);
tagged.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT, false,
TAG_ONLY_SOME_REASONS), tmp);
}
if (isIndirectCRL) {
DerOutputStream tmp = new DerOutputStream();
tmp.putBoolean(isIndirectCRL);
tagged.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT, false,
TAG_INDIRECT_CRL), tmp);
}
if (hasOnlyAttributeCerts) {
DerOutputStream tmp = new DerOutputStream();
tmp.putBoolean(hasOnlyAttributeCerts);
tagged.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT, false,
TAG_ONLY_ATTRIBUTE_CERTS), tmp);
}
DerOutputStream seq = new DerOutputStream();
seq.write(DerValue.tag_Sequence, tagged);
this.extensionValue = seq.toByteArray();
}
/**
* Returns the extension as user readable string.
*/
public String toString() {
StringBuilder sb = new StringBuilder(super.toString());
sb.append("IssuingDistributionPoint [\n ");
if (distributionPoint != null) {
sb.append(distributionPoint);
}
if (revocationReasons != null) {
sb.append(revocationReasons);
}
sb.append((hasOnlyUserCerts)
? (" Only contains user certs: true")
: (" Only contains user certs: false")).append("\n");
sb.append((hasOnlyCACerts)
? (" Only contains CA certs: true")
: (" Only contains CA certs: false")).append("\n");
sb.append((hasOnlyAttributeCerts)
? (" Only contains attribute certs: true")
: (" Only contains attribute certs: false")).append("\n");
sb.append((isIndirectCRL)
? (" Indirect CRL: true")
: (" Indirect CRL: false")).append("\n");
sb.append("]\n");
return sb.toString();
}
}

View File

@@ -0,0 +1,154 @@
/*
* Copyright (c) 1997, 1999, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.security.PublicKey;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import sun.misc.HexDumpEncoder;
import sun.security.util.*;
/**
* Represent the Key Identifier ASN.1 object.
*
* @author Amit Kapoor
* @author Hemma Prafullchandra
*/
public class KeyIdentifier {
private byte[] octetString;
/**
* Create a KeyIdentifier with the passed bit settings.
*
* @param octetString the octet string identifying the key identifier.
*/
public KeyIdentifier(byte[] octetString) {
this.octetString = octetString.clone();
}
/**
* Create a KeyIdentifier from the DER encoded value.
*
* @param val the DerValue
*/
public KeyIdentifier(DerValue val) throws IOException {
octetString = val.getOctetString();
}
/**
* Creates a KeyIdentifier from a public-key value.
*
* <p>From RFC2459: Two common methods for generating key identifiers from
* the public key are:
* <ol>
* <li>The keyIdentifier is composed of the 160-bit SHA-1 hash of the
* value of the BIT STRING subjectPublicKey (excluding the tag,
* length, and number of unused bits).
* <p>
* <li>The keyIdentifier is composed of a four bit type field with
* the value 0100 followed by the least significant 60 bits of the
* SHA-1 hash of the value of the BIT STRING subjectPublicKey.
* </ol>
* <p>This method supports method 1.
*
* @param pubKey the public key from which to construct this KeyIdentifier
* @throws IOException on parsing errors
*/
public KeyIdentifier(PublicKey pubKey)
throws IOException
{
DerValue algAndKey = new DerValue(pubKey.getEncoded());
if (algAndKey.tag != DerValue.tag_Sequence)
throw new IOException("PublicKey value is not a valid "
+ "X.509 public key");
AlgorithmId algid = AlgorithmId.parse(algAndKey.data.getDerValue());
byte[] key = algAndKey.data.getUnalignedBitString().toByteArray();
MessageDigest md = null;
try {
md = MessageDigest.getInstance("SHA1");
} catch (NoSuchAlgorithmException e3) {
throw new IOException("SHA1 not supported");
}
md.update(key);
this.octetString = md.digest();
}
/**
* Return the value of the KeyIdentifier as byte array.
*/
public byte[] getIdentifier() {
return octetString.clone();
}
/**
* Returns a printable representation of the KeyUsage.
*/
public String toString() {
String s = "KeyIdentifier [\n";
HexDumpEncoder encoder = new HexDumpEncoder();
s += encoder.encodeBuffer(octetString);
s += "]\n";
return (s);
}
/**
* Write the KeyIdentifier to the DerOutputStream.
*
* @param out the DerOutputStream to write the object to.
* @exception IOException
*/
void encode(DerOutputStream out) throws IOException {
out.putOctetString(octetString);
}
/**
* Returns a hash code value for this object.
* Objects that are equal will also have the same hashcode.
*/
public int hashCode () {
int retval = 0;
for (int i = 0; i < octetString.length; i++)
retval += octetString[i] * i;
return retval;
}
/**
* Indicates whether some other object is "equal to" this one.
*/
public boolean equals(Object other) {
if (this == other)
return true;
if (!(other instanceof KeyIdentifier))
return false;
byte[] otherString = ((KeyIdentifier)other).octetString;
return java.util.Arrays.equals(octetString, otherString);
}
}

View File

@@ -0,0 +1,363 @@
/*
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Enumeration;
import sun.security.util.*;
/**
* Represent the Key Usage Extension.
*
* <p>This extension, if present, defines the purpose (e.g., encipherment,
* signature, certificate signing) of the key contained in the certificate.
* The usage restriction might be employed when a multipurpose key is to be
* restricted (e.g., when an RSA key should be used only for signing or only
* for key encipherment).
*
* @author Amit Kapoor
* @author Hemma Prafullchandra
* @see Extension
* @see CertAttrSet
*/
public class KeyUsageExtension extends Extension
implements CertAttrSet<String> {
/**
* Identifier for this attribute, to be used with the
* get, set, delete methods of Certificate, x509 type.
*/
public static final String IDENT = "x509.info.extensions.KeyUsage";
/**
* Attribute names.
*/
public static final String NAME = "KeyUsage";
public static final String DIGITAL_SIGNATURE = "digital_signature";
public static final String NON_REPUDIATION = "non_repudiation";
public static final String KEY_ENCIPHERMENT = "key_encipherment";
public static final String DATA_ENCIPHERMENT = "data_encipherment";
public static final String KEY_AGREEMENT = "key_agreement";
public static final String KEY_CERTSIGN = "key_certsign";
public static final String CRL_SIGN = "crl_sign";
public static final String ENCIPHER_ONLY = "encipher_only";
public static final String DECIPHER_ONLY = "decipher_only";
// Private data members
private boolean[] bitString;
// Encode this extension value
private void encodeThis() throws IOException {
DerOutputStream os = new DerOutputStream();
os.putTruncatedUnalignedBitString(new BitArray(this.bitString));
this.extensionValue = os.toByteArray();
}
/**
* Check if bit is set.
*
* @param position the position in the bit string to check.
*/
private boolean isSet(int position) {
return (position < bitString.length) &&
bitString[position];
}
/**
* Set the bit at the specified position.
*/
private void set(int position, boolean val) {
// enlarge bitString if necessary
if (position >= bitString.length) {
boolean[] tmp = new boolean[position+1];
System.arraycopy(bitString, 0, tmp, 0, bitString.length);
bitString = tmp;
}
bitString[position] = val;
}
/**
* Create a KeyUsageExtension with the passed bit settings. The criticality
* is set to true.
*
* @param bitString the bits to be set for the extension.
*/
public KeyUsageExtension(byte[] bitString) throws IOException {
this.bitString =
new BitArray(bitString.length*8,bitString).toBooleanArray();
this.extensionId = PKIXExtensions.KeyUsage_Id;
this.critical = true;
encodeThis();
}
/**
* Create a KeyUsageExtension with the passed bit settings. The criticality
* is set to true.
*
* @param bitString the bits to be set for the extension.
*/
public KeyUsageExtension(boolean[] bitString) throws IOException {
this.bitString = bitString;
this.extensionId = PKIXExtensions.KeyUsage_Id;
this.critical = true;
encodeThis();
}
/**
* Create a KeyUsageExtension with the passed bit settings. The criticality
* is set to true.
*
* @param bitString the bits to be set for the extension.
*/
public KeyUsageExtension(BitArray bitString) throws IOException {
this.bitString = bitString.toBooleanArray();
this.extensionId = PKIXExtensions.KeyUsage_Id;
this.critical = true;
encodeThis();
}
/**
* Create the extension from the passed DER encoded value of the same.
* The DER encoded value may be wrapped in an OCTET STRING.
*
* @param critical true if the extension is to be treated as critical.
* @param value an array of DER encoded bytes of the actual value (possibly
* wrapped in an OCTET STRING).
* @exception ClassCastException if value is not an array of bytes
* @exception IOException on error.
*/
public KeyUsageExtension(Boolean critical, Object value)
throws IOException {
this.extensionId = PKIXExtensions.KeyUsage_Id;
this.critical = critical.booleanValue();
/*
* The following check should be activated again after
* the PKIX profiling work becomes standard and the check
* is not a barrier to interoperability !
* if (!this.critical) {
* throw new IOException("KeyUsageExtension not marked critical,"
* + " invalid profile.");
* }
*/
byte[] extValue = (byte[]) value;
if (extValue[0] == DerValue.tag_OctetString) {
this.extensionValue = new DerValue(extValue).getOctetString();
} else {
this.extensionValue = extValue;
}
DerValue val = new DerValue(this.extensionValue);
this.bitString = val.getUnalignedBitString().toBooleanArray();
}
/**
* Create a default key usage.
*/
public KeyUsageExtension() {
extensionId = PKIXExtensions.KeyUsage_Id;
critical = true;
bitString = new boolean[0];
}
/**
* Set the attribute value.
*/
public void set(String name, Object obj) throws IOException {
if (!(obj instanceof Boolean)) {
throw new IOException("Attribute must be of type Boolean.");
}
boolean val = ((Boolean)obj).booleanValue();
if (name.equalsIgnoreCase(DIGITAL_SIGNATURE)) {
set(0,val);
} else if (name.equalsIgnoreCase(NON_REPUDIATION)) {
set(1,val);
} else if (name.equalsIgnoreCase(KEY_ENCIPHERMENT)) {
set(2,val);
} else if (name.equalsIgnoreCase(DATA_ENCIPHERMENT)) {
set(3,val);
} else if (name.equalsIgnoreCase(KEY_AGREEMENT)) {
set(4,val);
} else if (name.equalsIgnoreCase(KEY_CERTSIGN)) {
set(5,val);
} else if (name.equalsIgnoreCase(CRL_SIGN)) {
set(6,val);
} else if (name.equalsIgnoreCase(ENCIPHER_ONLY)) {
set(7,val);
} else if (name.equalsIgnoreCase(DECIPHER_ONLY)) {
set(8,val);
} else {
throw new IOException("Attribute name not recognized by"
+ " CertAttrSet:KeyUsage.");
}
encodeThis();
}
/**
* Get the attribute value.
*/
public Boolean get(String name) throws IOException {
if (name.equalsIgnoreCase(DIGITAL_SIGNATURE)) {
return Boolean.valueOf(isSet(0));
} else if (name.equalsIgnoreCase(NON_REPUDIATION)) {
return Boolean.valueOf(isSet(1));
} else if (name.equalsIgnoreCase(KEY_ENCIPHERMENT)) {
return Boolean.valueOf(isSet(2));
} else if (name.equalsIgnoreCase(DATA_ENCIPHERMENT)) {
return Boolean.valueOf(isSet(3));
} else if (name.equalsIgnoreCase(KEY_AGREEMENT)) {
return Boolean.valueOf(isSet(4));
} else if (name.equalsIgnoreCase(KEY_CERTSIGN)) {
return Boolean.valueOf(isSet(5));
} else if (name.equalsIgnoreCase(CRL_SIGN)) {
return Boolean.valueOf(isSet(6));
} else if (name.equalsIgnoreCase(ENCIPHER_ONLY)) {
return Boolean.valueOf(isSet(7));
} else if (name.equalsIgnoreCase(DECIPHER_ONLY)) {
return Boolean.valueOf(isSet(8));
} else {
throw new IOException("Attribute name not recognized by"
+ " CertAttrSet:KeyUsage.");
}
}
/**
* Delete the attribute value.
*/
public void delete(String name) throws IOException {
if (name.equalsIgnoreCase(DIGITAL_SIGNATURE)) {
set(0,false);
} else if (name.equalsIgnoreCase(NON_REPUDIATION)) {
set(1,false);
} else if (name.equalsIgnoreCase(KEY_ENCIPHERMENT)) {
set(2,false);
} else if (name.equalsIgnoreCase(DATA_ENCIPHERMENT)) {
set(3,false);
} else if (name.equalsIgnoreCase(KEY_AGREEMENT)) {
set(4,false);
} else if (name.equalsIgnoreCase(KEY_CERTSIGN)) {
set(5,false);
} else if (name.equalsIgnoreCase(CRL_SIGN)) {
set(6,false);
} else if (name.equalsIgnoreCase(ENCIPHER_ONLY)) {
set(7,false);
} else if (name.equalsIgnoreCase(DECIPHER_ONLY)) {
set(8,false);
} else {
throw new IOException("Attribute name not recognized by"
+ " CertAttrSet:KeyUsage.");
}
encodeThis();
}
/**
* Returns a printable representation of the KeyUsage.
*/
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(super.toString());
sb.append("KeyUsage [\n");
if (isSet(0)) {
sb.append(" DigitalSignature\n");
}
if (isSet(1)) {
sb.append(" Non_repudiation\n");
}
if (isSet(2)) {
sb.append(" Key_Encipherment\n");
}
if (isSet(3)) {
sb.append(" Data_Encipherment\n");
}
if (isSet(4)) {
sb.append(" Key_Agreement\n");
}
if (isSet(5)) {
sb.append(" Key_CertSign\n");
}
if (isSet(6)) {
sb.append(" Crl_Sign\n");
}
if (isSet(7)) {
sb.append(" Encipher_Only\n");
}
if (isSet(8)) {
sb.append(" Decipher_Only\n");
}
sb.append("]\n");
return sb.toString();
}
/**
* Write the extension to the DerOutputStream.
*
* @param out the DerOutputStream to write the extension to.
* @exception IOException on encoding errors.
*/
public void encode(OutputStream out) throws IOException {
DerOutputStream tmp = new DerOutputStream();
if (this.extensionValue == null) {
this.extensionId = PKIXExtensions.KeyUsage_Id;
this.critical = true;
encodeThis();
}
super.encode(tmp);
out.write(tmp.toByteArray());
}
/**
* Return an enumeration of names of attributes existing within this
* attribute.
*/
public Enumeration<String> getElements() {
AttributeNameEnumeration elements = new AttributeNameEnumeration();
elements.addElement(DIGITAL_SIGNATURE);
elements.addElement(NON_REPUDIATION);
elements.addElement(KEY_ENCIPHERMENT);
elements.addElement(DATA_ENCIPHERMENT);
elements.addElement(KEY_AGREEMENT);
elements.addElement(KEY_CERTSIGN);
elements.addElement(CRL_SIGN);
elements.addElement(ENCIPHER_ONLY);
elements.addElement(DECIPHER_ONLY);
return (elements.elements());
}
public boolean[] getBits() {
return bitString.clone();
}
/**
* Return the name of this attribute.
*/
public String getName() {
return (NAME);
}
}

View File

@@ -0,0 +1,632 @@
/*
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.io.OutputStream;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.*;
import javax.security.auth.x500.X500Principal;
import sun.net.util.IPAddressUtil;
import sun.security.util.*;
import sun.security.pkcs.PKCS9Attribute;
/**
* This class defines the Name Constraints Extension.
* <p>
* The name constraints extension provides permitted and excluded
* subtrees that place restrictions on names that may be included within
* a certificate issued by a given CA. Restrictions may apply to the
* subject distinguished name or subject alternative names. Any name
* matching a restriction in the excluded subtrees field is invalid
* regardless of information appearing in the permitted subtrees.
* <p>
* The ASN.1 syntax for this is:
* <pre>
* NameConstraints ::= SEQUENCE {
* permittedSubtrees [0] GeneralSubtrees OPTIONAL,
* excludedSubtrees [1] GeneralSubtrees OPTIONAL
* }
* GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
* </pre>
*
* @author Amit Kapoor
* @author Hemma Prafullchandra
* @see Extension
* @see CertAttrSet
*/
public class NameConstraintsExtension extends Extension
implements CertAttrSet<String>, Cloneable {
/**
* Identifier for this attribute, to be used with the
* get, set, delete methods of Certificate, x509 type.
*/
public static final String IDENT = "x509.info.extensions.NameConstraints";
/**
* Attribute names.
*/
public static final String NAME = "NameConstraints";
public static final String PERMITTED_SUBTREES = "permitted_subtrees";
public static final String EXCLUDED_SUBTREES = "excluded_subtrees";
// Private data members
private static final byte TAG_PERMITTED = 0;
private static final byte TAG_EXCLUDED = 1;
private GeneralSubtrees permitted = null;
private GeneralSubtrees excluded = null;
private boolean hasMin;
private boolean hasMax;
private boolean minMaxValid = false;
// Recalculate hasMin and hasMax flags.
private void calcMinMax() throws IOException {
hasMin = false;
hasMax = false;
if (excluded != null) {
for (int i = 0; i < excluded.size(); i++) {
GeneralSubtree subtree = excluded.get(i);
if (subtree.getMinimum() != 0)
hasMin = true;
if (subtree.getMaximum() != -1)
hasMax = true;
}
}
if (permitted != null) {
for (int i = 0; i < permitted.size(); i++) {
GeneralSubtree subtree = permitted.get(i);
if (subtree.getMinimum() != 0)
hasMin = true;
if (subtree.getMaximum() != -1)
hasMax = true;
}
}
minMaxValid = true;
}
// Encode this extension value.
private void encodeThis() throws IOException {
minMaxValid = false;
if (permitted == null && excluded == null) {
this.extensionValue = null;
return;
}
DerOutputStream seq = new DerOutputStream();
DerOutputStream tagged = new DerOutputStream();
if (permitted != null) {
DerOutputStream tmp = new DerOutputStream();
permitted.encode(tmp);
tagged.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT,
true, TAG_PERMITTED), tmp);
}
if (excluded != null) {
DerOutputStream tmp = new DerOutputStream();
excluded.encode(tmp);
tagged.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT,
true, TAG_EXCLUDED), tmp);
}
seq.write(DerValue.tag_Sequence, tagged);
this.extensionValue = seq.toByteArray();
}
/**
* The default constructor for this class. Both parameters
* are optional and can be set to null. The extension criticality
* is set to true.
*
* @param permitted the permitted GeneralSubtrees (null for optional).
* @param excluded the excluded GeneralSubtrees (null for optional).
*/
public NameConstraintsExtension(GeneralSubtrees permitted,
GeneralSubtrees excluded)
throws IOException {
this.permitted = permitted;
this.excluded = excluded;
this.extensionId = PKIXExtensions.NameConstraints_Id;
this.critical = true;
encodeThis();
}
/**
* Create the extension from the passed DER encoded value.
*
* @param critical true if the extension is to be treated as critical.
* @param value an array of DER encoded bytes of the actual value.
* @exception ClassCastException if value is not an array of bytes
* @exception IOException on error.
*/
public NameConstraintsExtension(Boolean critical, Object value)
throws IOException {
this.extensionId = PKIXExtensions.NameConstraints_Id;
this.critical = critical.booleanValue();
this.extensionValue = (byte[]) value;
DerValue val = new DerValue(this.extensionValue);
if (val.tag != DerValue.tag_Sequence) {
throw new IOException("Invalid encoding for" +
" NameConstraintsExtension.");
}
// NB. this is always encoded with the IMPLICIT tag
// The checks only make sense if we assume implicit tagging,
// with explicit tagging the form is always constructed.
// Note that all the fields in NameConstraints are defined as
// being OPTIONAL, i.e., there could be an empty SEQUENCE, resulting
// in val.data being null.
if (val.data == null)
return;
while (val.data.available() != 0) {
DerValue opt = val.data.getDerValue();
if (opt.isContextSpecific(TAG_PERMITTED) && opt.isConstructed()) {
if (permitted != null) {
throw new IOException("Duplicate permitted " +
"GeneralSubtrees in NameConstraintsExtension.");
}
opt.resetTag(DerValue.tag_Sequence);
permitted = new GeneralSubtrees(opt);
} else if (opt.isContextSpecific(TAG_EXCLUDED) &&
opt.isConstructed()) {
if (excluded != null) {
throw new IOException("Duplicate excluded " +
"GeneralSubtrees in NameConstraintsExtension.");
}
opt.resetTag(DerValue.tag_Sequence);
excluded = new GeneralSubtrees(opt);
} else
throw new IOException("Invalid encoding of " +
"NameConstraintsExtension.");
}
minMaxValid = false;
}
/**
* Return the printable string.
*/
public String toString() {
return (super.toString() + "NameConstraints: [" +
((permitted == null) ? "" :
("\n Permitted:" + permitted.toString())) +
((excluded == null) ? "" :
("\n Excluded:" + excluded.toString()))
+ " ]\n");
}
/**
* Write the extension to the OutputStream.
*
* @param out the OutputStream to write the extension to.
* @exception IOException on encoding errors.
*/
public void encode(OutputStream out) throws IOException {
DerOutputStream tmp = new DerOutputStream();
if (this.extensionValue == null) {
this.extensionId = PKIXExtensions.NameConstraints_Id;
this.critical = true;
encodeThis();
}
super.encode(tmp);
out.write(tmp.toByteArray());
}
/**
* Set the attribute value.
*/
public void set(String name, Object obj) throws IOException {
if (name.equalsIgnoreCase(PERMITTED_SUBTREES)) {
if (!(obj instanceof GeneralSubtrees)) {
throw new IOException("Attribute value should be"
+ " of type GeneralSubtrees.");
}
permitted = (GeneralSubtrees)obj;
} else if (name.equalsIgnoreCase(EXCLUDED_SUBTREES)) {
if (!(obj instanceof GeneralSubtrees)) {
throw new IOException("Attribute value should be "
+ "of type GeneralSubtrees.");
}
excluded = (GeneralSubtrees)obj;
} else {
throw new IOException("Attribute name not recognized by " +
"CertAttrSet:NameConstraintsExtension.");
}
encodeThis();
}
/**
* Get the attribute value.
*/
public GeneralSubtrees get(String name) throws IOException {
if (name.equalsIgnoreCase(PERMITTED_SUBTREES)) {
return (permitted);
} else if (name.equalsIgnoreCase(EXCLUDED_SUBTREES)) {
return (excluded);
} else {
throw new IOException("Attribute name not recognized by " +
"CertAttrSet:NameConstraintsExtension.");
}
}
/**
* Delete the attribute value.
*/
public void delete(String name) throws IOException {
if (name.equalsIgnoreCase(PERMITTED_SUBTREES)) {
permitted = null;
} else if (name.equalsIgnoreCase(EXCLUDED_SUBTREES)) {
excluded = null;
} else {
throw new IOException("Attribute name not recognized by " +
"CertAttrSet:NameConstraintsExtension.");
}
encodeThis();
}
/**
* Return an enumeration of names of attributes existing within this
* attribute.
*/
public Enumeration<String> getElements() {
AttributeNameEnumeration elements = new AttributeNameEnumeration();
elements.addElement(PERMITTED_SUBTREES);
elements.addElement(EXCLUDED_SUBTREES);
return (elements.elements());
}
/**
* Return the name of this attribute.
*/
public String getName() {
return (NAME);
}
/**
* Merge additional name constraints with existing ones.
* This function is used in certification path processing
* to accumulate name constraints from successive certificates
* in the path. Note that NameConstraints can never be
* expanded by a merge, just remain constant or become more
* limiting.
* <p>
* IETF RFC2459 specifies the processing of Name Constraints as
* follows:
* <p>
* (j) If permittedSubtrees is present in the certificate, set the
* constrained subtrees state variable to the intersection of its
* previous value and the value indicated in the extension field.
* <p>
* (k) If excludedSubtrees is present in the certificate, set the
* excluded subtrees state variable to the union of its previous
* value and the value indicated in the extension field.
* <p>
* @param newConstraints additional NameConstraints to be applied
* @throws IOException on error
*/
public void merge(NameConstraintsExtension newConstraints)
throws IOException {
if (newConstraints == null) {
// absence of any explicit constraints implies unconstrained
return;
}
/*
* If excludedSubtrees is present in the certificate, set the
* excluded subtrees state variable to the union of its previous
* value and the value indicated in the extension field.
*/
GeneralSubtrees newExcluded = newConstraints.get(EXCLUDED_SUBTREES);
if (excluded == null) {
excluded = (newExcluded != null) ?
(GeneralSubtrees)newExcluded.clone() : null;
} else {
if (newExcluded != null) {
// Merge new excluded with current excluded (union)
excluded.union(newExcluded);
}
}
/*
* If permittedSubtrees is present in the certificate, set the
* constrained subtrees state variable to the intersection of its
* previous value and the value indicated in the extension field.
*/
GeneralSubtrees newPermitted = newConstraints.get(PERMITTED_SUBTREES);
if (permitted == null) {
permitted = (newPermitted != null) ?
(GeneralSubtrees)newPermitted.clone() : null;
} else {
if (newPermitted != null) {
// Merge new permitted with current permitted (intersection)
newExcluded = permitted.intersect(newPermitted);
// Merge new excluded subtrees to current excluded (union)
if (newExcluded != null) {
if (excluded != null) {
excluded.union(newExcluded);
} else {
excluded = (GeneralSubtrees)newExcluded.clone();
}
}
}
}
// Optional optimization: remove permitted subtrees that are excluded.
// This is not necessary for algorithm correctness, but it makes
// subsequent operations on the NameConstraints faster and require
// less space.
if (permitted != null) {
permitted.reduce(excluded);
}
// The NameConstraints have been changed, so re-encode them. Methods in
// this class assume that the encodings have already been done.
encodeThis();
}
/**
* check whether a certificate conforms to these NameConstraints.
* This involves verifying that the subject name and subjectAltName
* extension (critical or noncritical) is consistent with the permitted
* subtrees state variables. Also verify that the subject name and
* subjectAltName extension (critical or noncritical) is consistent with
* the excluded subtrees state variables.
*
* @param cert X509Certificate to be verified
* @returns true if certificate verifies successfully
* @throws IOException on error
*/
public boolean verify(X509Certificate cert) throws IOException {
if (cert == null) {
throw new IOException("Certificate is null");
}
// Calculate hasMin and hasMax booleans (if necessary)
if (!minMaxValid) {
calcMinMax();
}
if (hasMin) {
throw new IOException("Non-zero minimum BaseDistance in"
+ " name constraints not supported");
}
if (hasMax) {
throw new IOException("Maximum BaseDistance in"
+ " name constraints not supported");
}
X500Principal subjectPrincipal = cert.getSubjectX500Principal();
X500Name subject = X500Name.asX500Name(subjectPrincipal);
// Check subject as an X500Name
if (subject.isEmpty() == false) {
if (verify(subject) == false) {
return false;
}
}
GeneralNames altNames = null;
// extract altNames
try {
// extract extensions, if any, from certInfo
// following returns null if certificate contains no extensions
X509CertImpl certImpl = X509CertImpl.toImpl(cert);
SubjectAlternativeNameExtension altNameExt =
certImpl.getSubjectAlternativeNameExtension();
if (altNameExt != null) {
// extract altNames from extension; this call does not
// return an IOException on null altnames
altNames = altNameExt.get(
SubjectAlternativeNameExtension.SUBJECT_NAME);
}
} catch (CertificateException ce) {
throw new IOException("Unable to extract extensions from " +
"certificate: " + ce.getMessage());
}
if (altNames == null) {
altNames = new GeneralNames();
// RFC 5280 4.2.1.10:
// When constraints are imposed on the rfc822Name name form,
// but the certificate does not include a subject alternative name,
// the rfc822Name constraint MUST be applied to the attribute of
// type emailAddress in the subject distinguished name.
for (AVA ava : subject.allAvas()) {
ObjectIdentifier attrOID = ava.getObjectIdentifier();
if (attrOID.equals(PKCS9Attribute.EMAIL_ADDRESS_OID)) {
String attrValue = ava.getValueString();
if (attrValue != null) {
try {
altNames.add(new GeneralName(
new RFC822Name(attrValue)));
} catch (IOException ioe) {
continue;
}
}
}
}
}
// If there is no IPAddressName or DNSName in subjectAlternativeNames,
// see if the last CN inside subjectName can be used instead.
DerValue derValue = subject.findMostSpecificAttribute
(X500Name.commonName_oid);
String cn = derValue == null ? null : derValue.getAsString();
if (cn != null) {
try {
if (IPAddressUtil.isIPv4LiteralAddress(cn) ||
IPAddressUtil.isIPv6LiteralAddress(cn)) {
if (!hasNameType(altNames, GeneralNameInterface.NAME_IP)) {
altNames.add(new GeneralName(new IPAddressName(cn)));
}
} else {
if (!hasNameType(altNames, GeneralNameInterface.NAME_DNS)) {
altNames.add(new GeneralName(new DNSName(cn)));
}
}
} catch (IOException ioe) {
// OK, cn is neither IP nor DNS
}
}
// verify each subjectAltName
for (int i = 0; i < altNames.size(); i++) {
GeneralNameInterface altGNI = altNames.get(i).getName();
if (!verify(altGNI)) {
return false;
}
}
// All tests passed.
return true;
}
private static boolean hasNameType(GeneralNames names, int type) {
for (GeneralName name : names.names()) {
if (name.getType() == type) {
return true;
}
}
return false;
}
/**
* check whether a name conforms to these NameConstraints.
* This involves verifying that the name is consistent with the
* permitted and excluded subtrees variables.
*
* @param name GeneralNameInterface name to be verified
* @returns true if certificate verifies successfully
* @throws IOException on error
*/
public boolean verify(GeneralNameInterface name) throws IOException {
if (name == null) {
throw new IOException("name is null");
}
// Verify that the name is consistent with the excluded subtrees
if (excluded != null && excluded.size() > 0) {
for (int i = 0; i < excluded.size(); i++) {
GeneralSubtree gs = excluded.get(i);
if (gs == null)
continue;
GeneralName gn = gs.getName();
if (gn == null)
continue;
GeneralNameInterface exName = gn.getName();
if (exName == null)
continue;
// if name matches or narrows any excluded subtree,
// return false
switch (exName.constrains(name)) {
case GeneralNameInterface.NAME_DIFF_TYPE:
case GeneralNameInterface.NAME_WIDENS: // name widens excluded
case GeneralNameInterface.NAME_SAME_TYPE:
break;
case GeneralNameInterface.NAME_MATCH:
case GeneralNameInterface.NAME_NARROWS: // subject name excluded
return false;
}
}
}
// Verify that the name is consistent with the permitted subtrees
if (permitted != null && permitted.size() > 0) {
boolean sameType = false;
for (int i = 0; i < permitted.size(); i++) {
GeneralSubtree gs = permitted.get(i);
if (gs == null)
continue;
GeneralName gn = gs.getName();
if (gn == null)
continue;
GeneralNameInterface perName = gn.getName();
if (perName == null)
continue;
// if Name matches any type in permitted,
// and Name does not match or narrow some permitted subtree,
// return false
switch (perName.constrains(name)) {
case GeneralNameInterface.NAME_DIFF_TYPE:
continue; // continue checking other permitted names
case GeneralNameInterface.NAME_WIDENS: // name widens permitted
case GeneralNameInterface.NAME_SAME_TYPE:
sameType = true;
continue; // continue to look for a match or narrow
case GeneralNameInterface.NAME_MATCH:
case GeneralNameInterface.NAME_NARROWS:
// name narrows permitted
return true; // name is definitely OK, so break out of loop
}
}
if (sameType) {
return false;
}
}
return true;
}
/**
* Clone all objects that may be modified during certificate validation.
*/
public Object clone() {
try {
NameConstraintsExtension newNCE =
(NameConstraintsExtension) super.clone();
if (permitted != null) {
newNCE.permitted = (GeneralSubtrees) permitted.clone();
}
if (excluded != null) {
newNCE.excluded = (GeneralSubtrees) excluded.clone();
}
return newNCE;
} catch (CloneNotSupportedException cnsee) {
throw new RuntimeException("CloneNotSupportedException while " +
"cloning NameConstraintsException. This should never happen.");
}
}
}

View File

@@ -0,0 +1,329 @@
/*
* Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.io.OutputStream;
import java.util.*;
import sun.security.util.*;
/**
* Represents Netscape Certificate Type Extension.
* The details are defined
* <a href=http://www.netscape.com/eng/security/comm4-cert-exts.html>
* here </a>.
*
* <p>This extension, if present, defines both the purpose
* (e.g., encipherment, signature, certificate signing) and the application
* (e.g., SSL, S/Mime or Object Signing of the key contained in the
* certificate. This extension has been superseded by IETF PKIX extensions
* but is provided here for compatibility reasons.
*
* @author Hemma Prafullchandra
* @see Extension
* @see CertAttrSet
*/
public class NetscapeCertTypeExtension extends Extension
implements CertAttrSet<String> {
/**
* Identifier for this attribute, to be used with the
* get, set, delete methods of Certificate, x509 type.
*/
public static final String IDENT = "x509.info.extensions.NetscapeCertType";
/**
* Attribute names.
*/
public static final String NAME = "NetscapeCertType";
public static final String SSL_CLIENT = "ssl_client";
public static final String SSL_SERVER = "ssl_server";
public static final String S_MIME = "s_mime";
public static final String OBJECT_SIGNING = "object_signing";
public static final String SSL_CA = "ssl_ca";
public static final String S_MIME_CA = "s_mime_ca";
public static final String OBJECT_SIGNING_CA = "object_signing_ca";
private static final int CertType_data[] = { 2, 16, 840, 1, 113730, 1, 1 };
/**
* Object identifier for the Netscape-Cert-Type extension.
*/
public static ObjectIdentifier NetscapeCertType_Id;
static {
try {
NetscapeCertType_Id = new ObjectIdentifier(CertType_data);
} catch (IOException ioe) {
// should not happen
}
}
private boolean[] bitString;
private static class MapEntry {
String mName;
int mPosition;
MapEntry(String name, int position) {
mName = name;
mPosition = position;
}
}
private static MapEntry[] mMapData = {
new MapEntry(SSL_CLIENT, 0),
new MapEntry(SSL_SERVER, 1),
new MapEntry(S_MIME, 2),
new MapEntry(OBJECT_SIGNING, 3),
// note that bit 4 is reserved
new MapEntry(SSL_CA, 5),
new MapEntry(S_MIME_CA, 6),
new MapEntry(OBJECT_SIGNING_CA, 7),
};
private static final Vector<String> mAttributeNames = new Vector<String>();
static {
for (MapEntry entry : mMapData) {
mAttributeNames.add(entry.mName);
}
}
private static int getPosition(String name) throws IOException {
for (int i = 0; i < mMapData.length; i++) {
if (name.equalsIgnoreCase(mMapData[i].mName))
return mMapData[i].mPosition;
}
throw new IOException("Attribute name [" + name
+ "] not recognized by CertAttrSet:NetscapeCertType.");
}
// Encode this extension value
private void encodeThis() throws IOException {
DerOutputStream os = new DerOutputStream();
os.putTruncatedUnalignedBitString(new BitArray(this.bitString));
this.extensionValue = os.toByteArray();
}
/**
* Check if bit is set.
*
* @param position the position in the bit string to check.
*/
private boolean isSet(int position) {
return (position < bitString.length) &&
bitString[position];
}
/**
* Set the bit at the specified position.
*/
private void set(int position, boolean val) {
// enlarge bitString if necessary
if (position >= bitString.length) {
boolean[] tmp = new boolean[position+1];
System.arraycopy(bitString, 0, tmp, 0, bitString.length);
bitString = tmp;
}
bitString[position] = val;
}
/**
* Create a NetscapeCertTypeExtension with the passed bit settings.
* The criticality is set to true.
*
* @param bitString the bits to be set for the extension.
*/
public NetscapeCertTypeExtension(byte[] bitString) throws IOException {
this.bitString =
new BitArray(bitString.length*8, bitString).toBooleanArray();
this.extensionId = NetscapeCertType_Id;
this.critical = true;
encodeThis();
}
/**
* Create a NetscapeCertTypeExtension with the passed bit settings.
* The criticality is set to true.
*
* @param bitString the bits to be set for the extension.
*/
public NetscapeCertTypeExtension(boolean[] bitString) throws IOException {
this.bitString = bitString;
this.extensionId = NetscapeCertType_Id;
this.critical = true;
encodeThis();
}
/**
* Create the extension from the passed DER encoded value of the same.
*
* @param critical true if the extension is to be treated as critical.
* @param value an array of DER encoded bytes of the actual value.
* @exception ClassCastException if value is not an array of bytes
* @exception IOException on error.
*/
public NetscapeCertTypeExtension(Boolean critical, Object value)
throws IOException {
this.extensionId = NetscapeCertType_Id;
this.critical = critical.booleanValue();
this.extensionValue = (byte[]) value;
DerValue val = new DerValue(this.extensionValue);
this.bitString = val.getUnalignedBitString().toBooleanArray();
}
/**
* Create a default key usage.
*/
public NetscapeCertTypeExtension() {
extensionId = NetscapeCertType_Id;
critical = true;
bitString = new boolean[0];
}
/**
* Set the attribute value.
*/
public void set(String name, Object obj) throws IOException {
if (!(obj instanceof Boolean))
throw new IOException("Attribute must be of type Boolean.");
boolean val = ((Boolean)obj).booleanValue();
set(getPosition(name), val);
encodeThis();
}
/**
* Get the attribute value.
*/
public Boolean get(String name) throws IOException {
return Boolean.valueOf(isSet(getPosition(name)));
}
/**
* Delete the attribute value.
*/
public void delete(String name) throws IOException {
set(getPosition(name), false);
encodeThis();
}
/**
* Returns a printable representation of the NetscapeCertType.
*/
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(super.toString());
sb.append("NetscapeCertType [\n");
if (isSet(0)) {
sb.append(" SSL client\n");
}
if (isSet(1)) {
sb.append(" SSL server\n");
}
if (isSet(2)) {
sb.append(" S/MIME\n");
}
if (isSet(3)) {
sb.append(" Object Signing\n");
}
if (isSet(5)) {
sb.append(" SSL CA\n");
}
if (isSet(6)) {
sb.append(" S/MIME CA\n");
}
if (isSet(7)) {
sb.append(" Object Signing CA");
}
sb.append("]\n");
return sb.toString();
}
/**
* Write the extension to the DerOutputStream.
*
* @param out the DerOutputStream to write the extension to.
* @exception IOException on encoding errors.
*/
public void encode(OutputStream out) throws IOException {
DerOutputStream tmp = new DerOutputStream();
if (this.extensionValue == null) {
this.extensionId = NetscapeCertType_Id;
this.critical = true;
encodeThis();
}
super.encode(tmp);
out.write(tmp.toByteArray());
}
/**
* Return an enumeration of names of attributes existing within this
* attribute.
*/
public Enumeration<String> getElements() {
return mAttributeNames.elements();
}
/**
* Return the name of this attribute.
*/
public String getName() {
return (NAME);
}
/**
* Get a boolean array representing the bits of this extension,
* as it maps to the KeyUsage extension.
* @return the bit values of this extension mapped to the bit values
* of the KeyUsage extension as an array of booleans.
*/
public boolean[] getKeyUsageMappedBits() {
KeyUsageExtension keyUsage = new KeyUsageExtension();
Boolean val = Boolean.TRUE;
try {
if (isSet(getPosition(SSL_CLIENT)) ||
isSet(getPosition(S_MIME)) ||
isSet(getPosition(OBJECT_SIGNING)))
keyUsage.set(KeyUsageExtension.DIGITAL_SIGNATURE, val);
if (isSet(getPosition(SSL_SERVER)))
keyUsage.set(KeyUsageExtension.KEY_ENCIPHERMENT, val);
if (isSet(getPosition(SSL_CA)) ||
isSet(getPosition(S_MIME_CA)) ||
isSet(getPosition(OBJECT_SIGNING_CA)))
keyUsage.set(KeyUsageExtension.KEY_CERTSIGN, val);
} catch (IOException e) { }
return keyUsage.getBits();
}
}

View File

@@ -0,0 +1,132 @@
/*
* Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Enumeration;
import sun.security.util.*;
/**
* Represent the OCSP NoCheck Extension from RFC2560.
* <p>
* A CA may specify that an OCSP client can trust a responder for the
* lifetime of the responder's certificate. The CA does so by including
* the extension id-pkix-ocsp-nocheck. This SHOULD be a non-critical
* extension. The value of the extension should be NULL. CAs issuing
* such a certificate should realized that a compromise of the
* responder's key, is as serious as the compromise of a CA key used to
* sign CRLs, at least for the validity period of this certificate. CA's
* may choose to issue this type of certificate with a very short
* lifetime and renew it frequently.
* <pre>
* id-pkix-ocsp-nocheck OBJECT IDENTIFIER ::= { id-pkix-ocsp 5 }
* </pre>
*
* @author Xuelei Fan
* @see Extension
* @see CertAttrSet
*/
public class OCSPNoCheckExtension extends Extension
implements CertAttrSet<String> {
/**
* Identifier for this attribute, to be used with the
* get, set, delete methods of Certificate, x509 type.
*/
public static final String IDENT =
"x509.info.extensions.OCSPNoCheck";
/**
* Attribute names.
*/
public static final String NAME = "OCSPNoCheck";
/**
* Create a OCSPNoCheckExtension
*/
public OCSPNoCheckExtension() throws IOException {
this.extensionId = PKIXExtensions.OCSPNoCheck_Id;
this.critical = false;
this.extensionValue = new byte[0];
}
/**
* Create the extension from the passed DER encoded value.
*
* @param critical true if the extension is to be treated as critical.
* @param value an array of DER encoded bytes of the actual value.
* @exception IOException on error.
*/
public OCSPNoCheckExtension(Boolean critical, Object value)
throws IOException {
this.extensionId = PKIXExtensions.OCSPNoCheck_Id;
this.critical = critical.booleanValue();
// the value should be null, just ignore it here.
this.extensionValue = new byte[0];
}
/**
* Set the attribute value.
*/
public void set(String name, Object obj) throws IOException {
throw new IOException("No attribute is allowed by " +
"CertAttrSet:OCSPNoCheckExtension.");
}
/**
* Get the attribute value.
*/
public Object get(String name) throws IOException {
throw new IOException("No attribute is allowed by " +
"CertAttrSet:OCSPNoCheckExtension.");
}
/**
* Delete the attribute value.
*/
public void delete(String name) throws IOException {
throw new IOException("No attribute is allowed by " +
"CertAttrSet:OCSPNoCheckExtension.");
}
/**
* Return an enumeration of names of attributes existing within this
* attribute.
*/
public Enumeration<String> getElements() {
return (new AttributeNameEnumeration()).elements();
}
/**
* Return the name of this attribute.
*/
public String getName() {
return NAME;
}
}

View File

@@ -0,0 +1,295 @@
/*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.util.*;
import java.io.IOException;
import java.security.cert.CertificateException;
import sun.security.util.*;
/**
* This class defines the mapping from OID & name to classes and vice
* versa. Used by CertificateExtensions & PKCS10 to get the java
* classes associated with a particular OID/name.
*
* @author Amit Kapoor
* @author Hemma Prafullchandra
* @author Andreas Sterbenz
*
*/
public class OIDMap {
private OIDMap() {
// empty
}
// "user-friendly" names
private static final String ROOT = X509CertImpl.NAME + "." +
X509CertInfo.NAME + "." +
X509CertInfo.EXTENSIONS;
private static final String AUTH_KEY_IDENTIFIER = ROOT + "." +
AuthorityKeyIdentifierExtension.NAME;
private static final String SUB_KEY_IDENTIFIER = ROOT + "." +
SubjectKeyIdentifierExtension.NAME;
private static final String KEY_USAGE = ROOT + "." +
KeyUsageExtension.NAME;
private static final String PRIVATE_KEY_USAGE = ROOT + "." +
PrivateKeyUsageExtension.NAME;
private static final String POLICY_MAPPINGS = ROOT + "." +
PolicyMappingsExtension.NAME;
private static final String SUB_ALT_NAME = ROOT + "." +
SubjectAlternativeNameExtension.NAME;
private static final String ISSUER_ALT_NAME = ROOT + "." +
IssuerAlternativeNameExtension.NAME;
private static final String BASIC_CONSTRAINTS = ROOT + "." +
BasicConstraintsExtension.NAME;
private static final String NAME_CONSTRAINTS = ROOT + "." +
NameConstraintsExtension.NAME;
private static final String POLICY_CONSTRAINTS = ROOT + "." +
PolicyConstraintsExtension.NAME;
private static final String CRL_NUMBER = ROOT + "." +
CRLNumberExtension.NAME;
private static final String CRL_REASON = ROOT + "." +
CRLReasonCodeExtension.NAME;
private static final String NETSCAPE_CERT = ROOT + "." +
NetscapeCertTypeExtension.NAME;
private static final String CERT_POLICIES = ROOT + "." +
CertificatePoliciesExtension.NAME;
private static final String EXT_KEY_USAGE = ROOT + "." +
ExtendedKeyUsageExtension.NAME;
private static final String INHIBIT_ANY_POLICY = ROOT + "." +
InhibitAnyPolicyExtension.NAME;
private static final String CRL_DIST_POINTS = ROOT + "." +
CRLDistributionPointsExtension.NAME;
private static final String CERT_ISSUER = ROOT + "." +
CertificateIssuerExtension.NAME;
private static final String SUBJECT_INFO_ACCESS = ROOT + "." +
SubjectInfoAccessExtension.NAME;
private static final String AUTH_INFO_ACCESS = ROOT + "." +
AuthorityInfoAccessExtension.NAME;
private static final String ISSUING_DIST_POINT = ROOT + "." +
IssuingDistributionPointExtension.NAME;
private static final String DELTA_CRL_INDICATOR = ROOT + "." +
DeltaCRLIndicatorExtension.NAME;
private static final String FRESHEST_CRL = ROOT + "." +
FreshestCRLExtension.NAME;
private static final String OCSPNOCHECK = ROOT + "." +
OCSPNoCheckExtension.NAME;
private static final int NetscapeCertType_data[] =
{ 2, 16, 840, 1, 113730, 1, 1 };
/** Map ObjectIdentifier(oid) -> OIDInfo(info) */
private final static Map<ObjectIdentifier,OIDInfo> oidMap;
/** Map String(friendly name) -> OIDInfo(info) */
private final static Map<String,OIDInfo> nameMap;
static {
oidMap = new HashMap<ObjectIdentifier,OIDInfo>();
nameMap = new HashMap<String,OIDInfo>();
addInternal(SUB_KEY_IDENTIFIER, PKIXExtensions.SubjectKey_Id,
"sun.security.x509.SubjectKeyIdentifierExtension");
addInternal(KEY_USAGE, PKIXExtensions.KeyUsage_Id,
"sun.security.x509.KeyUsageExtension");
addInternal(PRIVATE_KEY_USAGE, PKIXExtensions.PrivateKeyUsage_Id,
"sun.security.x509.PrivateKeyUsageExtension");
addInternal(SUB_ALT_NAME, PKIXExtensions.SubjectAlternativeName_Id,
"sun.security.x509.SubjectAlternativeNameExtension");
addInternal(ISSUER_ALT_NAME, PKIXExtensions.IssuerAlternativeName_Id,
"sun.security.x509.IssuerAlternativeNameExtension");
addInternal(BASIC_CONSTRAINTS, PKIXExtensions.BasicConstraints_Id,
"sun.security.x509.BasicConstraintsExtension");
addInternal(CRL_NUMBER, PKIXExtensions.CRLNumber_Id,
"sun.security.x509.CRLNumberExtension");
addInternal(CRL_REASON, PKIXExtensions.ReasonCode_Id,
"sun.security.x509.CRLReasonCodeExtension");
addInternal(NAME_CONSTRAINTS, PKIXExtensions.NameConstraints_Id,
"sun.security.x509.NameConstraintsExtension");
addInternal(POLICY_MAPPINGS, PKIXExtensions.PolicyMappings_Id,
"sun.security.x509.PolicyMappingsExtension");
addInternal(AUTH_KEY_IDENTIFIER, PKIXExtensions.AuthorityKey_Id,
"sun.security.x509.AuthorityKeyIdentifierExtension");
addInternal(POLICY_CONSTRAINTS, PKIXExtensions.PolicyConstraints_Id,
"sun.security.x509.PolicyConstraintsExtension");
addInternal(NETSCAPE_CERT, ObjectIdentifier.newInternal
(new int[] {2,16,840,1,113730,1,1}),
"sun.security.x509.NetscapeCertTypeExtension");
addInternal(CERT_POLICIES, PKIXExtensions.CertificatePolicies_Id,
"sun.security.x509.CertificatePoliciesExtension");
addInternal(EXT_KEY_USAGE, PKIXExtensions.ExtendedKeyUsage_Id,
"sun.security.x509.ExtendedKeyUsageExtension");
addInternal(INHIBIT_ANY_POLICY, PKIXExtensions.InhibitAnyPolicy_Id,
"sun.security.x509.InhibitAnyPolicyExtension");
addInternal(CRL_DIST_POINTS, PKIXExtensions.CRLDistributionPoints_Id,
"sun.security.x509.CRLDistributionPointsExtension");
addInternal(CERT_ISSUER, PKIXExtensions.CertificateIssuer_Id,
"sun.security.x509.CertificateIssuerExtension");
addInternal(SUBJECT_INFO_ACCESS, PKIXExtensions.SubjectInfoAccess_Id,
"sun.security.x509.SubjectInfoAccessExtension");
addInternal(AUTH_INFO_ACCESS, PKIXExtensions.AuthInfoAccess_Id,
"sun.security.x509.AuthorityInfoAccessExtension");
addInternal(ISSUING_DIST_POINT,
PKIXExtensions.IssuingDistributionPoint_Id,
"sun.security.x509.IssuingDistributionPointExtension");
addInternal(DELTA_CRL_INDICATOR, PKIXExtensions.DeltaCRLIndicator_Id,
"sun.security.x509.DeltaCRLIndicatorExtension");
addInternal(FRESHEST_CRL, PKIXExtensions.FreshestCRL_Id,
"sun.security.x509.FreshestCRLExtension");
addInternal(OCSPNOCHECK, PKIXExtensions.OCSPNoCheck_Id,
"sun.security.x509.OCSPNoCheckExtension");
}
/**
* Add attributes to the table. For internal use in the static
* initializer.
*/
private static void addInternal(String name, ObjectIdentifier oid,
String className) {
OIDInfo info = new OIDInfo(name, oid, className);
oidMap.put(oid, info);
nameMap.put(name, info);
}
/**
* Inner class encapsulating the mapping info and Class loading.
*/
private static class OIDInfo {
final ObjectIdentifier oid;
final String name;
final String className;
private volatile Class<?> clazz;
OIDInfo(String name, ObjectIdentifier oid, String className) {
this.name = name;
this.oid = oid;
this.className = className;
}
OIDInfo(String name, ObjectIdentifier oid, Class<?> clazz) {
this.name = name;
this.oid = oid;
this.className = clazz.getName();
this.clazz = clazz;
}
/**
* Return the Class object associated with this attribute.
*/
Class<?> getClazz() throws CertificateException {
try {
Class<?> c = clazz;
if (c == null) {
c = Class.forName(className);
clazz = c;
}
return c;
} catch (ClassNotFoundException e) {
throw new CertificateException("Could not load class: " + e, e);
}
}
}
/**
* Add a name to lookup table.
*
* @param name the name of the attr
* @param oid the string representation of the object identifier for
* the class.
* @param clazz the Class object associated with this attribute
* @exception CertificateException on errors.
*/
public static void addAttribute(String name, String oid, Class<?> clazz)
throws CertificateException {
ObjectIdentifier objId;
try {
objId = new ObjectIdentifier(oid);
} catch (IOException ioe) {
throw new CertificateException
("Invalid Object identifier: " + oid);
}
OIDInfo info = new OIDInfo(name, objId, clazz);
if (oidMap.put(objId, info) != null) {
throw new CertificateException
("Object identifier already exists: " + oid);
}
if (nameMap.put(name, info) != null) {
throw new CertificateException("Name already exists: " + name);
}
}
/**
* Return user friendly name associated with the OID.
*
* @param oid the name of the object identifier to be returned.
* @return the user friendly name or null if no name
* is registered for this oid.
*/
public static String getName(ObjectIdentifier oid) {
OIDInfo info = oidMap.get(oid);
return (info == null) ? null : info.name;
}
/**
* Return Object identifier for user friendly name.
*
* @param name the user friendly name.
* @return the Object Identifier or null if no oid
* is registered for this name.
*/
public static ObjectIdentifier getOID(String name) {
OIDInfo info = nameMap.get(name);
return (info == null) ? null : info.oid;
}
/**
* Return the java class object associated with the user friendly name.
*
* @param name the user friendly name.
* @exception CertificateException if class cannot be instantiated.
*/
public static Class<?> getClass(String name) throws CertificateException {
OIDInfo info = nameMap.get(name);
return (info == null) ? null : info.getClazz();
}
/**
* Return the java class object associated with the object identifier.
*
* @param oid the name of the object identifier to be returned.
* @exception CertificateException if class cannot be instatiated.
*/
public static Class<?> getClass(ObjectIdentifier oid)
throws CertificateException {
OIDInfo info = oidMap.get(oid);
return (info == null) ? null : info.getClazz();
}
}

View File

@@ -0,0 +1,175 @@
/*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import sun.security.util.*;
/**
* This class implements the OIDName as required by the GeneralNames
* ASN.1 object.
*
* @author Amit Kapoor
* @author Hemma Prafullchandra
* @see GeneralName
* @see GeneralNames
* @see GeneralNameInterface
*/
public class OIDName implements GeneralNameInterface {
private ObjectIdentifier oid;
/**
* Create the OIDName object from the passed encoded Der value.
*
* @param derValue the encoded DER OIDName.
* @exception IOException on error.
*/
public OIDName(DerValue derValue) throws IOException {
oid = derValue.getOID();
}
/**
* Create the OIDName object with the specified name.
*
* @param name the OIDName.
*/
public OIDName(ObjectIdentifier oid) {
this.oid = oid;
}
/**
* Create the OIDName from the String form of the OID
*
* @param name the OIDName in form "x.y.z..."
* @throws IOException on error
*/
public OIDName(String name) throws IOException {
try {
oid = new ObjectIdentifier(name);
} catch (Exception e) {
throw new IOException("Unable to create OIDName: " + e);
}
}
/**
* Return the type of the GeneralName.
*/
public int getType() {
return (GeneralNameInterface.NAME_OID);
}
/**
* Encode the OID name into the DerOutputStream.
*
* @param out the DER stream to encode the OIDName to.
* @exception IOException on encoding errors.
*/
public void encode(DerOutputStream out) throws IOException {
out.putOID(oid);
}
/**
* Convert the name into user readable string.
*/
public String toString() {
return ("OIDName: " + oid.toString());
}
/**
* Returns this OID name.
*/
public ObjectIdentifier getOID() {
return oid;
}
/**
* Compares this name with another, for equality.
*
* @return true iff the names are identical
*/
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!(obj instanceof OIDName))
return false;
OIDName other = (OIDName)obj;
return oid.equals((Object)other.oid);
}
/**
* Returns the hash code value for this object.
*
* @return a hash code value for this object.
*/
public int hashCode() {
return oid.hashCode();
}
/**
* Return type of constraint inputName places on this name:<ul>
* <li>NAME_DIFF_TYPE = -1: input name is different type from name (i.e. does not constrain).
* <li>NAME_MATCH = 0: input name matches name.
* <li>NAME_NARROWS = 1: input name narrows name (is lower in the naming subtree)
* <li>NAME_WIDENS = 2: input name widens name (is higher in the naming subtree)
* <li>NAME_SAME_TYPE = 3: input name does not match or narrow name, but is same type.
* </ul>. These results are used in checking NameConstraints during
* certification path verification.
*
* @param inputName to be checked for being constrained
* @returns constraint type above
* @throws UnsupportedOperationException if name is not exact match, but narrowing and widening are
* not supported for this name type.
*/
public int constrains(GeneralNameInterface inputName) throws UnsupportedOperationException {
int constraintType;
if (inputName == null)
constraintType = NAME_DIFF_TYPE;
else if (inputName.getType() != NAME_OID)
constraintType = NAME_DIFF_TYPE;
else if (this.equals((OIDName)inputName))
constraintType = NAME_MATCH;
else
//widens and narrows not defined in RFC2459 for OIDName (aka registeredID)
throw new UnsupportedOperationException("Narrowing and widening are not supported for OIDNames");
return constraintType;
}
/**
* Return subtree depth of this name for purposes of determining
* NameConstraints minimum and maximum bounds and for calculating
* path lengths in name subtrees.
*
* @returns distance of name from root
* @throws UnsupportedOperationException if not supported for this name type
*/
public int subtreeDepth() throws UnsupportedOperationException {
throw new UnsupportedOperationException("subtreeDepth() not supported for OIDName.");
}
}

View File

@@ -0,0 +1,269 @@
/*
* Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.util.Arrays;
import sun.security.util.*;
/**
* This class represents the OtherName as required by the GeneralNames
* ASN.1 object. It supplies the generic framework to allow specific
* Other Name types, and also provides minimal support for unrecognized
* Other Name types.
*
* The ASN.1 definition for OtherName is:
* <pre>
* OtherName ::= SEQUENCE {
* type-id OBJECT IDENTIFIER,
* value [0] EXPLICIT ANY DEFINED BY type-id
* }
* </pre>
* @author Hemma Prafullchandra
*/
public class OtherName implements GeneralNameInterface {
private String name;
private ObjectIdentifier oid;
private byte[] nameValue = null;
private GeneralNameInterface gni = null;
private static final byte TAG_VALUE = 0;
private int myhash = -1;
/**
* Create the OtherName object from a passed ObjectIdentfier and
* byte array name value
*
* @param oid ObjectIdentifier of this OtherName object
* @param value the DER-encoded value of the OtherName
* @throws IOException on error
*/
public OtherName(ObjectIdentifier oid, byte[] value) throws IOException {
if (oid == null || value == null) {
throw new NullPointerException("parameters may not be null");
}
this.oid = oid;
this.nameValue = value;
gni = getGNI(oid, value);
if (gni != null) {
name = gni.toString();
} else {
name = "Unrecognized ObjectIdentifier: " + oid.toString();
}
}
/**
* Create the OtherName object from the passed encoded Der value.
*
* @param derValue the encoded DER OtherName.
* @exception IOException on error.
*/
public OtherName(DerValue derValue) throws IOException {
DerInputStream in = derValue.toDerInputStream();
oid = in.getOID();
DerValue val = in.getDerValue();
nameValue = val.toByteArray();
gni = getGNI(oid, nameValue);
if (gni != null) {
name = gni.toString();
} else {
name = "Unrecognized ObjectIdentifier: " + oid.toString();
}
}
/**
* Get ObjectIdentifier
*/
public ObjectIdentifier getOID() {
//XXXX May want to consider cloning this
return oid;
}
/**
* Get name value
*/
public byte[] getNameValue() {
return nameValue.clone();
}
/**
* Get GeneralNameInterface
*/
private GeneralNameInterface getGNI(ObjectIdentifier oid, byte[] nameValue)
throws IOException {
try {
Class<?> extClass = OIDMap.getClass(oid);
if (extClass == null) { // Unsupported OtherName
return null;
}
Class<?>[] params = { Object.class };
Constructor<?> cons = extClass.getConstructor(params);
Object[] passed = new Object[] { nameValue };
GeneralNameInterface gni =
(GeneralNameInterface)cons.newInstance(passed);
return gni;
} catch (Exception e) {
throw new IOException("Instantiation error: " + e, e);
}
}
/**
* Return the type of the GeneralName.
*/
public int getType() {
return GeneralNameInterface.NAME_ANY;
}
/**
* Encode the Other name into the DerOutputStream.
*
* @param out the DER stream to encode the Other-Name to.
* @exception IOException on encoding errors.
*/
public void encode(DerOutputStream out) throws IOException {
if (gni != null) {
// This OtherName has a supported class
gni.encode(out);
return;
} else {
// This OtherName has no supporting class
DerOutputStream tmp = new DerOutputStream();
tmp.putOID(oid);
tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, TAG_VALUE), nameValue);
out.write(DerValue.tag_Sequence, tmp);
}
}
/**
* Compares this name with another, for equality.
*
* @return true iff the names are identical.
*/
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof OtherName)) {
return false;
}
OtherName otherOther = (OtherName)other;
if (!(otherOther.oid.equals((Object)oid))) {
return false;
}
GeneralNameInterface otherGNI = null;
try {
otherGNI = getGNI(otherOther.oid, otherOther.nameValue);
} catch (IOException ioe) {
return false;
}
boolean result;
if (otherGNI != null) {
try {
result = (otherGNI.constrains(this) == NAME_MATCH);
} catch (UnsupportedOperationException ioe) {
result = false;
}
} else {
result = Arrays.equals(nameValue, otherOther.nameValue);
}
return result;
}
/**
* Returns the hash code for this OtherName.
*
* @return a hash code value.
*/
public int hashCode() {
if (myhash == -1) {
myhash = 37 + oid.hashCode();
for (int i = 0; i < nameValue.length; i++) {
myhash = 37 * myhash + nameValue[i];
}
}
return myhash;
}
/**
* Convert the name into user readable string.
*/
public String toString() {
return "Other-Name: " + name;
}
/**
* Return type of constraint inputName places on this name:<ul>
* <li>NAME_DIFF_TYPE = -1: input name is different type from name
* (i.e. does not constrain).
* <li>NAME_MATCH = 0: input name matches name.
* <li>NAME_NARROWS = 1: input name narrows name (is lower in the
* naming subtree)
* <li>NAME_WIDENS = 2: input name widens name (is higher in the
* naming subtree)
* <li>NAME_SAME_TYPE = 3: input name does not match or narrow name,
* but is same type.
* </ul>. These results are used in checking NameConstraints during
* certification path verification.
*
* @param inputName to be checked for being constrained
* @returns constraint type above
* @throws UnsupportedOperationException if name is same type, but
* comparison operations are not supported for this name type.
*/
public int constrains(GeneralNameInterface inputName) {
int constraintType;
if (inputName == null) {
constraintType = NAME_DIFF_TYPE;
} else if (inputName.getType() != NAME_ANY) {
constraintType = NAME_DIFF_TYPE;
} else {
throw new UnsupportedOperationException("Narrowing, widening, "
+ "and matching are not supported for OtherName.");
}
return constraintType;
}
/**
* Return subtree depth of this name for purposes of determining
* NameConstraints minimum and maximum bounds.
*
* @returns distance of name from root
* @throws UnsupportedOperationException if not supported for this name type
*/
public int subtreeDepth() {
throw new UnsupportedOperationException
("subtreeDepth() not supported for generic OtherName");
}
}

View File

@@ -0,0 +1,284 @@
/*
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.*;
import sun.security.util.*;
/**
* Lists all the object identifiers of the X509 extensions of the PKIX profile.
*
* <p>Extensions are addiitonal attributes which can be inserted in a X509
* v3 certificate. For example a "Driving License Certificate" could have
* the driving license number as a extension.
*
* <p>Extensions are represented as a sequence of the extension identifier
* (Object Identifier), a boolean flag stating whether the extension is to
* be treated as being critical and the extension value itself (this is again
* a DER encoding of the extension value).
*
* @see Extension
*
*
* @author Amit Kapoor
* @author Hemma Prafullchandra
*/
public class PKIXExtensions {
// The object identifiers
private static final int[] AuthorityKey_data = { 2, 5, 29, 35 };
private static final int[] SubjectKey_data = { 2, 5, 29, 14 };
private static final int[] KeyUsage_data = { 2, 5, 29, 15 };
private static final int[] PrivateKeyUsage_data = { 2, 5, 29, 16 };
private static final int[] CertificatePolicies_data = { 2, 5, 29, 32 };
private static final int[] PolicyMappings_data = { 2, 5, 29, 33 };
private static final int[] SubjectAlternativeName_data = { 2, 5, 29, 17 };
private static final int[] IssuerAlternativeName_data = { 2, 5, 29, 18 };
private static final int[] SubjectDirectoryAttributes_data = { 2, 5, 29, 9 };
private static final int[] BasicConstraints_data = { 2, 5, 29, 19 };
private static final int[] NameConstraints_data = { 2, 5, 29, 30 };
private static final int[] PolicyConstraints_data = { 2, 5, 29, 36 };
private static final int[] CRLDistributionPoints_data = { 2, 5, 29, 31 };
private static final int[] CRLNumber_data = { 2, 5, 29, 20 };
private static final int[] IssuingDistributionPoint_data = { 2, 5, 29, 28 };
private static final int[] DeltaCRLIndicator_data = { 2, 5, 29, 27 };
private static final int[] ReasonCode_data = { 2, 5, 29, 21 };
private static final int[] HoldInstructionCode_data = { 2, 5, 29, 23 };
private static final int[] InvalidityDate_data = { 2, 5, 29, 24 };
private static final int[] ExtendedKeyUsage_data = { 2, 5, 29, 37 };
private static final int[] InhibitAnyPolicy_data = { 2, 5, 29, 54 };
private static final int[] CertificateIssuer_data = { 2, 5, 29, 29 };
private static final int[] AuthInfoAccess_data = { 1, 3, 6, 1, 5, 5, 7, 1, 1};
private static final int[] SubjectInfoAccess_data = { 1, 3, 6, 1, 5, 5, 7, 1, 11};
private static final int[] FreshestCRL_data = { 2, 5, 29, 46 };
private static final int[] OCSPNoCheck_data = { 1, 3, 6, 1, 5, 5, 7,
48, 1, 5};
// Additional extensions under the PKIX arc that are not necessarily
// used in X.509 Certificates or CRLs.
private static final int[] OCSPNonce_data = { 1, 3, 6, 1, 5, 5, 7,
48, 1, 2};
/**
* Identifies the particular public key used to sign the certificate.
*/
public static final ObjectIdentifier AuthorityKey_Id;
/**
* Identifies the particular public key used in an application.
*/
public static final ObjectIdentifier SubjectKey_Id;
/**
* Defines the purpose of the key contained in the certificate.
*/
public static final ObjectIdentifier KeyUsage_Id;
/**
* Allows the certificate issuer to specify a different validity period
* for the private key than the certificate.
*/
public static final ObjectIdentifier PrivateKeyUsage_Id;
/**
* Contains the sequence of policy information terms.
*/
public static final ObjectIdentifier CertificatePolicies_Id;
/**
* Lists pairs of object identifiers of policies considered equivalent by
* the issuing CA to the subject CA.
*/
public static final ObjectIdentifier PolicyMappings_Id;
/**
* Allows additional identities to be bound to the subject of the
* certificate.
*/
public static final ObjectIdentifier SubjectAlternativeName_Id;
/**
* Allows additional identities to be associated with the certificate
* issuer.
*/
public static final ObjectIdentifier IssuerAlternativeName_Id;
/**
* Identifies additional directory attributes.
* This extension is always non-critical.
*/
public static final ObjectIdentifier SubjectDirectoryAttributes_Id;
/**
* Identifies whether the subject of the certificate is a CA and how deep
* a certification path may exist through that CA.
*/
public static final ObjectIdentifier BasicConstraints_Id;
/**
* Provides for permitted and excluded subtrees that place restrictions
* on names that may be included within a certificate issued by a given CA.
*/
public static final ObjectIdentifier NameConstraints_Id;
/**
* Used to either prohibit policy mapping or limit the set of policies
* that can be in subsequent certificates.
*/
public static final ObjectIdentifier PolicyConstraints_Id;
/**
* Identifies how CRL information is obtained.
*/
public static final ObjectIdentifier CRLDistributionPoints_Id;
/**
* Conveys a monotonically increasing sequence number for each CRL
* issued by a given CA.
*/
public static final ObjectIdentifier CRLNumber_Id;
/**
* Identifies the CRL distribution point for a particular CRL.
*/
public static final ObjectIdentifier IssuingDistributionPoint_Id;
/**
* Identifies the delta CRL.
*/
public static final ObjectIdentifier DeltaCRLIndicator_Id;
/**
* Identifies the reason for the certificate revocation.
*/
public static final ObjectIdentifier ReasonCode_Id;
/**
* This extension provides a registered instruction identifier indicating
* the action to be taken, after encountering a certificate that has been
* placed on hold.
*/
public static final ObjectIdentifier HoldInstructionCode_Id;
/**
* Identifies the date on which it is known or suspected that the private
* key was compromised or that the certificate otherwise became invalid.
*/
public static final ObjectIdentifier InvalidityDate_Id;
/**
* Identifies one or more purposes for which the certified public key
* may be used, in addition to or in place of the basic purposes
* indicated in the key usage extension field.
*/
public static final ObjectIdentifier ExtendedKeyUsage_Id;
/**
* Specifies whether any-policy policy OID is permitted
*/
public static final ObjectIdentifier InhibitAnyPolicy_Id;
/**
* Identifies the certificate issuer associated with an entry in an
* indirect CRL.
*/
public static final ObjectIdentifier CertificateIssuer_Id;
/**
* This extension indicates how to access CA information and services for
* the issuer of the certificate in which the extension appears.
* This information may be used for on-line certification validation
* services.
*/
public static final ObjectIdentifier AuthInfoAccess_Id;
/**
* This extension indicates how to access CA information and services for
* the subject of the certificate in which the extension appears.
*/
public static final ObjectIdentifier SubjectInfoAccess_Id;
/**
* Identifies how delta CRL information is obtained.
*/
public static final ObjectIdentifier FreshestCRL_Id;
/**
* Identifies the OCSP client can trust the responder for the
* lifetime of the responder's certificate.
*/
public static final ObjectIdentifier OCSPNoCheck_Id;
/**
* This extension is used to provide nonce data for OCSP requests
* or responses.
*/
public static final ObjectIdentifier OCSPNonce_Id;
static {
AuthorityKey_Id = ObjectIdentifier.newInternal(AuthorityKey_data);
SubjectKey_Id = ObjectIdentifier.newInternal(SubjectKey_data);
KeyUsage_Id = ObjectIdentifier.newInternal(KeyUsage_data);
PrivateKeyUsage_Id = ObjectIdentifier.newInternal(PrivateKeyUsage_data);
CertificatePolicies_Id =
ObjectIdentifier.newInternal(CertificatePolicies_data);
PolicyMappings_Id = ObjectIdentifier.newInternal(PolicyMappings_data);
SubjectAlternativeName_Id =
ObjectIdentifier.newInternal(SubjectAlternativeName_data);
IssuerAlternativeName_Id =
ObjectIdentifier.newInternal(IssuerAlternativeName_data);
ExtendedKeyUsage_Id = ObjectIdentifier.newInternal(ExtendedKeyUsage_data);
InhibitAnyPolicy_Id = ObjectIdentifier.newInternal(InhibitAnyPolicy_data);
SubjectDirectoryAttributes_Id =
ObjectIdentifier.newInternal(SubjectDirectoryAttributes_data);
BasicConstraints_Id =
ObjectIdentifier.newInternal(BasicConstraints_data);
ReasonCode_Id = ObjectIdentifier.newInternal(ReasonCode_data);
HoldInstructionCode_Id =
ObjectIdentifier.newInternal(HoldInstructionCode_data);
InvalidityDate_Id = ObjectIdentifier.newInternal(InvalidityDate_data);
NameConstraints_Id = ObjectIdentifier.newInternal(NameConstraints_data);
PolicyConstraints_Id =
ObjectIdentifier.newInternal(PolicyConstraints_data);
CRLDistributionPoints_Id =
ObjectIdentifier.newInternal(CRLDistributionPoints_data);
CRLNumber_Id =
ObjectIdentifier.newInternal(CRLNumber_data);
IssuingDistributionPoint_Id =
ObjectIdentifier.newInternal(IssuingDistributionPoint_data);
DeltaCRLIndicator_Id =
ObjectIdentifier.newInternal(DeltaCRLIndicator_data);
CertificateIssuer_Id =
ObjectIdentifier.newInternal(CertificateIssuer_data);
AuthInfoAccess_Id =
ObjectIdentifier.newInternal(AuthInfoAccess_data);
SubjectInfoAccess_Id =
ObjectIdentifier.newInternal(SubjectInfoAccess_data);
FreshestCRL_Id = ObjectIdentifier.newInternal(FreshestCRL_data);
OCSPNoCheck_Id = ObjectIdentifier.newInternal(OCSPNoCheck_data);
OCSPNonce_Id = ObjectIdentifier.newInternal(OCSPNonce_data);
}
}

View File

@@ -0,0 +1,278 @@
/*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.io.OutputStream;
import java.security.cert.CertificateException;
import java.util.Enumeration;
import java.util.Vector;
import sun.security.util.*;
/**
* This class defines the certificate extension which specifies the
* Policy constraints.
* <p>
* The policy constraints extension can be used in certificates issued
* to CAs. The policy constraints extension constrains path validation
* in two ways. It can be used to prohibit policy mapping or require
* that each certificate in a path contain an acceptable policy
* identifier.<p>
* The ASN.1 syntax for this is (IMPLICIT tagging is defined in the
* module definition):
* <pre>
* PolicyConstraints ::= SEQUENCE {
* requireExplicitPolicy [0] SkipCerts OPTIONAL,
* inhibitPolicyMapping [1] SkipCerts OPTIONAL
* }
* SkipCerts ::= INTEGER (0..MAX)
* </pre>
* @author Amit Kapoor
* @author Hemma Prafullchandra
* @see Extension
* @see CertAttrSet
*/
public class PolicyConstraintsExtension extends Extension
implements CertAttrSet<String> {
/**
* Identifier for this attribute, to be used with the
* get, set, delete methods of Certificate, x509 type.
*/
public static final String IDENT = "x509.info.extensions.PolicyConstraints";
/**
* Attribute names.
*/
public static final String NAME = "PolicyConstraints";
public static final String REQUIRE = "require";
public static final String INHIBIT = "inhibit";
private static final byte TAG_REQUIRE = 0;
private static final byte TAG_INHIBIT = 1;
private int require = -1;
private int inhibit = -1;
// Encode this extension value.
private void encodeThis() throws IOException {
if (require == -1 && inhibit == -1) {
this.extensionValue = null;
return;
}
DerOutputStream tagged = new DerOutputStream();
DerOutputStream seq = new DerOutputStream();
if (require != -1) {
DerOutputStream tmp = new DerOutputStream();
tmp.putInteger(require);
tagged.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT,
false, TAG_REQUIRE), tmp);
}
if (inhibit != -1) {
DerOutputStream tmp = new DerOutputStream();
tmp.putInteger(inhibit);
tagged.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT,
false, TAG_INHIBIT), tmp);
}
seq.write(DerValue.tag_Sequence, tagged);
this.extensionValue = seq.toByteArray();
}
/**
* Create a PolicyConstraintsExtension object with both
* require explicit policy and inhibit policy mapping. The
* extension is marked non-critical.
*
* @param require require explicit policy (-1 for optional).
* @param inhibit inhibit policy mapping (-1 for optional).
*/
public PolicyConstraintsExtension(int require, int inhibit)
throws IOException {
this(Boolean.FALSE, require, inhibit);
}
/**
* Create a PolicyConstraintsExtension object with specified
* criticality and both require explicit policy and inhibit
* policy mapping.
*
* @param critical true if the extension is to be treated as critical.
* @param require require explicit policy (-1 for optional).
* @param inhibit inhibit policy mapping (-1 for optional).
*/
public PolicyConstraintsExtension(Boolean critical, int require, int inhibit)
throws IOException {
this.require = require;
this.inhibit = inhibit;
this.extensionId = PKIXExtensions.PolicyConstraints_Id;
this.critical = critical.booleanValue();
encodeThis();
}
/**
* Create the extension from its DER encoded value and criticality.
*
* @param critical true if the extension is to be treated as critical.
* @param value an array of DER encoded bytes of the actual value.
* @exception ClassCastException if value is not an array of bytes
* @exception IOException on error.
*/
public PolicyConstraintsExtension(Boolean critical, Object value)
throws IOException {
this.extensionId = PKIXExtensions.PolicyConstraints_Id;
this.critical = critical.booleanValue();
this.extensionValue = (byte[]) value;
DerValue val = new DerValue(this.extensionValue);
if (val.tag != DerValue.tag_Sequence) {
throw new IOException("Sequence tag missing for PolicyConstraint.");
}
DerInputStream in = val.data;
while (in != null && in.available() != 0) {
DerValue next = in.getDerValue();
if (next.isContextSpecific(TAG_REQUIRE) && !next.isConstructed()) {
if (this.require != -1)
throw new IOException("Duplicate requireExplicitPolicy" +
"found in the PolicyConstraintsExtension");
next.resetTag(DerValue.tag_Integer);
this.require = next.getInteger();
} else if (next.isContextSpecific(TAG_INHIBIT) &&
!next.isConstructed()) {
if (this.inhibit != -1)
throw new IOException("Duplicate inhibitPolicyMapping" +
"found in the PolicyConstraintsExtension");
next.resetTag(DerValue.tag_Integer);
this.inhibit = next.getInteger();
} else
throw new IOException("Invalid encoding of PolicyConstraint");
}
}
/**
* Return the extension as user readable string.
*/
public String toString() {
String s;
s = super.toString() + "PolicyConstraints: [" + " Require: ";
if (require == -1)
s += "unspecified;";
else
s += require + ";";
s += "\tInhibit: ";
if (inhibit == -1)
s += "unspecified";
else
s += inhibit;
s += " ]\n";
return s;
}
/**
* Write the extension to the DerOutputStream.
*
* @param out the DerOutputStream to write the extension to.
* @exception IOException on encoding errors.
*/
public void encode(OutputStream out) throws IOException {
DerOutputStream tmp = new DerOutputStream();
if (extensionValue == null) {
extensionId = PKIXExtensions.PolicyConstraints_Id;
critical = false;
encodeThis();
}
super.encode(tmp);
out.write(tmp.toByteArray());
}
/**
* Set the attribute value.
*/
public void set(String name, Object obj) throws IOException {
if (!(obj instanceof Integer)) {
throw new IOException("Attribute value should be of type Integer.");
}
if (name.equalsIgnoreCase(REQUIRE)) {
require = ((Integer)obj).intValue();
} else if (name.equalsIgnoreCase(INHIBIT)) {
inhibit = ((Integer)obj).intValue();
} else {
throw new IOException("Attribute name " + "[" + name + "]" +
" not recognized by " +
"CertAttrSet:PolicyConstraints.");
}
encodeThis();
}
/**
* Get the attribute value.
*/
public Integer get(String name) throws IOException {
if (name.equalsIgnoreCase(REQUIRE)) {
return new Integer(require);
} else if (name.equalsIgnoreCase(INHIBIT)) {
return new Integer(inhibit);
} else {
throw new IOException("Attribute name not recognized by " +
"CertAttrSet:PolicyConstraints.");
}
}
/**
* Delete the attribute value.
*/
public void delete(String name) throws IOException {
if (name.equalsIgnoreCase(REQUIRE)) {
require = -1;
} else if (name.equalsIgnoreCase(INHIBIT)) {
inhibit = -1;
} else {
throw new IOException("Attribute name not recognized by " +
"CertAttrSet:PolicyConstraints.");
}
encodeThis();
}
/**
* Return an enumeration of names of attributes existing within this
* attribute.
*/
public Enumeration<String> getElements() {
AttributeNameEnumeration elements = new AttributeNameEnumeration();
elements.addElement(REQUIRE);
elements.addElement(INHIBIT);
return (elements.elements());
}
/**
* Return the name of this attribute.
*/
public String getName() {
return (NAME);
}
}

View File

@@ -0,0 +1,284 @@
/*
* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.security.cert.PolicyQualifierInfo;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;
import sun.security.util.DerValue;
import sun.security.util.DerOutputStream;
/**
* PolicyInformation is the class that contains a specific certificate policy
* that is part of the CertificatePoliciesExtension. A
* CertificatePolicyExtension value consists of a vector of these objects.
* <p>
* The ASN.1 syntax for PolicyInformation (IMPLICIT tagging is defined in the
* module definition):
* <pre>
*
* PolicyInformation ::= SEQUENCE {
* policyIdentifier CertPolicyId,
* policyQualifiers SEQUENCE SIZE (1..MAX) OF
* PolicyQualifierInfo OPTIONAL }
*
* CertPolicyId ::= OBJECT IDENTIFIER
*
* PolicyQualifierInfo ::= SEQUENCE {
* policyQualifierId PolicyQualifierId,
* qualifier ANY DEFINED BY policyQualifierId }
* </pre>
*
* @author Sean Mullan
* @author Anne Anderson
* @since 1.4
*/
public class PolicyInformation {
// Attribute names
public static final String NAME = "PolicyInformation";
public static final String ID = "id";
public static final String QUALIFIERS = "qualifiers";
/* The policy OID */
private CertificatePolicyId policyIdentifier;
/* A Set of java.security.cert.PolicyQualifierInfo objects */
private Set<PolicyQualifierInfo> policyQualifiers;
/**
* Create an instance of PolicyInformation
*
* @param policyIdentifier the policyIdentifier as a
* CertificatePolicyId
* @param policyQualifiers a Set of PolicyQualifierInfo objects.
* Must not be NULL. Specify an empty Set for no qualifiers.
* @exception IOException on decoding errors.
*/
public PolicyInformation(CertificatePolicyId policyIdentifier,
Set<PolicyQualifierInfo> policyQualifiers) throws IOException {
if (policyQualifiers == null) {
throw new NullPointerException("policyQualifiers is null");
}
this.policyQualifiers =
new LinkedHashSet<PolicyQualifierInfo>(policyQualifiers);
this.policyIdentifier = policyIdentifier;
}
/**
* Create an instance of PolicyInformation, decoding from
* the passed DerValue.
*
* @param val the DerValue to construct the PolicyInformation from.
* @exception IOException on decoding errors.
*/
public PolicyInformation(DerValue val) throws IOException {
if (val.tag != DerValue.tag_Sequence) {
throw new IOException("Invalid encoding of PolicyInformation");
}
policyIdentifier = new CertificatePolicyId(val.data.getDerValue());
if (val.data.available() != 0) {
policyQualifiers = new LinkedHashSet<PolicyQualifierInfo>();
DerValue opt = val.data.getDerValue();
if (opt.tag != DerValue.tag_Sequence)
throw new IOException("Invalid encoding of PolicyInformation");
if (opt.data.available() == 0)
throw new IOException("No data available in policyQualifiers");
while (opt.data.available() != 0)
policyQualifiers.add(new PolicyQualifierInfo
(opt.data.getDerValue().toByteArray()));
} else {
policyQualifiers = Collections.emptySet();
}
}
/**
* Compare this PolicyInformation with another object for equality
*
* @param other object to be compared with this
* @return true iff the PolicyInformation objects match
*/
public boolean equals(Object other) {
if (!(other instanceof PolicyInformation))
return false;
PolicyInformation piOther = (PolicyInformation)other;
if (!policyIdentifier.equals(piOther.getPolicyIdentifier()))
return false;
return policyQualifiers.equals(piOther.getPolicyQualifiers());
}
/**
* Returns the hash code for this PolicyInformation.
*
* @return a hash code value.
*/
public int hashCode() {
int myhash = 37 + policyIdentifier.hashCode();
myhash = 37 * myhash + policyQualifiers.hashCode();
return myhash;
}
/**
* Return the policyIdentifier value
*
* @return The CertificatePolicyId object containing
* the policyIdentifier (not a copy).
*/
public CertificatePolicyId getPolicyIdentifier() {
return policyIdentifier;
}
/**
* Return the policyQualifiers value
*
* @return a Set of PolicyQualifierInfo objects associated
* with this certificate policy (not a copy).
* Returns an empty Set if there are no qualifiers.
* Never returns null.
*/
public Set<PolicyQualifierInfo> getPolicyQualifiers() {
return policyQualifiers;
}
/**
* Get the attribute value.
*/
public Object get(String name) throws IOException {
if (name.equalsIgnoreCase(ID)) {
return policyIdentifier;
} else if (name.equalsIgnoreCase(QUALIFIERS)) {
return policyQualifiers;
} else {
throw new IOException("Attribute name [" + name +
"] not recognized by PolicyInformation.");
}
}
/**
* Set the attribute value.
*/
@SuppressWarnings("unchecked") // Checked with instanceof
public void set(String name, Object obj) throws IOException {
if (name.equalsIgnoreCase(ID)) {
if (obj instanceof CertificatePolicyId)
policyIdentifier = (CertificatePolicyId)obj;
else
throw new IOException("Attribute value must be instance " +
"of CertificatePolicyId.");
} else if (name.equalsIgnoreCase(QUALIFIERS)) {
if (policyIdentifier == null) {
throw new IOException("Attribute must have a " +
"CertificatePolicyIdentifier value before " +
"PolicyQualifierInfo can be set.");
}
if (obj instanceof Set) {
Iterator<?> i = ((Set<?>)obj).iterator();
while (i.hasNext()) {
Object obj1 = i.next();
if (!(obj1 instanceof PolicyQualifierInfo)) {
throw new IOException("Attribute value must be a" +
"Set of PolicyQualifierInfo objects.");
}
}
policyQualifiers = (Set<PolicyQualifierInfo>) obj;
} else {
throw new IOException("Attribute value must be of type Set.");
}
} else {
throw new IOException("Attribute name [" + name +
"] not recognized by PolicyInformation");
}
}
/**
* Delete the attribute value.
*/
public void delete(String name) throws IOException {
if (name.equalsIgnoreCase(QUALIFIERS)) {
policyQualifiers = Collections.emptySet();
} else if (name.equalsIgnoreCase(ID)) {
throw new IOException("Attribute ID may not be deleted from " +
"PolicyInformation.");
} else {
//ID may not be deleted
throw new IOException("Attribute name [" + name +
"] not recognized by PolicyInformation.");
}
}
/**
* Return an enumeration of names of attributes existing within this
* attribute.
*/
public Enumeration<String> getElements() {
AttributeNameEnumeration elements = new AttributeNameEnumeration();
elements.addElement(ID);
elements.addElement(QUALIFIERS);
return elements.elements();
}
/**
* Return the name of this attribute.
*/
public String getName() {
return NAME;
}
/**
* Return a printable representation of the PolicyInformation.
*/
public String toString() {
StringBuilder s = new StringBuilder(" [" + policyIdentifier.toString());
s.append(policyQualifiers + " ]\n");
return s.toString();
}
/**
* Write the PolicyInformation to the DerOutputStream.
*
* @param out the DerOutputStream to write the extension to.
* @exception IOException on encoding errors.
*/
public void encode(DerOutputStream out) throws IOException {
DerOutputStream tmp = new DerOutputStream();
policyIdentifier.encode(tmp);
if (!policyQualifiers.isEmpty()) {
DerOutputStream tmp2 = new DerOutputStream();
for (PolicyQualifierInfo pq : policyQualifiers) {
tmp2.write(pq.getEncoded());
}
tmp.write(DerValue.tag_Sequence, tmp2);
}
out.write(DerValue.tag_Sequence, tmp);
}
}

View File

@@ -0,0 +1,223 @@
/*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.io.OutputStream;
import java.util.*;
import sun.security.util.*;
/**
* Represent the Policy Mappings Extension.
*
* This extension, if present, identifies the certificate policies considered
* identical between the issuing and the subject CA.
* <p>Extensions are addiitonal attributes which can be inserted in a X509
* v3 certificate. For example a "Driving License Certificate" could have
* the driving license number as a extension.
*
* <p>Extensions are represented as a sequence of the extension identifier
* (Object Identifier), a boolean flag stating whether the extension is to
* be treated as being critical and the extension value itself (this is again
* a DER encoding of the extension value).
*
* @author Amit Kapoor
* @author Hemma Prafullchandra
* @see Extension
* @see CertAttrSet
*/
public class PolicyMappingsExtension extends Extension
implements CertAttrSet<String> {
/**
* Identifier for this attribute, to be used with the
* get, set, delete methods of Certificate, x509 type.
*/
public static final String IDENT = "x509.info.extensions.PolicyMappings";
/**
* Attribute names.
*/
public static final String NAME = "PolicyMappings";
public static final String MAP = "map";
// Private data members
private List<CertificatePolicyMap> maps;
// Encode this extension value
private void encodeThis() throws IOException {
if (maps == null || maps.isEmpty()) {
this.extensionValue = null;
return;
}
DerOutputStream os = new DerOutputStream();
DerOutputStream tmp = new DerOutputStream();
for (CertificatePolicyMap map : maps) {
map.encode(tmp);
}
os.write(DerValue.tag_Sequence, tmp);
this.extensionValue = os.toByteArray();
}
/**
* Create a PolicyMappings with the List of CertificatePolicyMap.
*
* @param maps the List of CertificatePolicyMap.
*/
public PolicyMappingsExtension(List<CertificatePolicyMap> map)
throws IOException {
this.maps = map;
this.extensionId = PKIXExtensions.PolicyMappings_Id;
this.critical = false;
encodeThis();
}
/**
* Create a default PolicyMappingsExtension.
*/
public PolicyMappingsExtension() {
extensionId = PKIXExtensions.KeyUsage_Id;
critical = false;
maps = Collections.<CertificatePolicyMap>emptyList();
}
/**
* Create the extension from the passed DER encoded value.
*
* @params critical true if the extension is to be treated as critical.
* @params value an array of DER encoded bytes of the actual value.
* @exception ClassCastException if value is not an array of bytes
* @exception IOException on error.
*/
public PolicyMappingsExtension(Boolean critical, Object value)
throws IOException {
this.extensionId = PKIXExtensions.PolicyMappings_Id;
this.critical = critical.booleanValue();
this.extensionValue = (byte[]) value;
DerValue val = new DerValue(this.extensionValue);
if (val.tag != DerValue.tag_Sequence) {
throw new IOException("Invalid encoding for " +
"PolicyMappingsExtension.");
}
maps = new ArrayList<CertificatePolicyMap>();
while (val.data.available() != 0) {
DerValue seq = val.data.getDerValue();
CertificatePolicyMap map = new CertificatePolicyMap(seq);
maps.add(map);
}
}
/**
* Returns a printable representation of the policy map.
*/
public String toString() {
if (maps == null) return "";
String s = super.toString() + "PolicyMappings [\n"
+ maps.toString() + "]\n";
return (s);
}
/**
* Write the extension to the OutputStream.
*
* @param out the OutputStream to write the extension to.
* @exception IOException on encoding errors.
*/
public void encode(OutputStream out) throws IOException {
DerOutputStream tmp = new DerOutputStream();
if (extensionValue == null) {
extensionId = PKIXExtensions.PolicyMappings_Id;
critical = false;
encodeThis();
}
super.encode(tmp);
out.write(tmp.toByteArray());
}
/**
* Set the attribute value.
*/
@SuppressWarnings("unchecked") // Checked with instanceof
public void set(String name, Object obj) throws IOException {
if (name.equalsIgnoreCase(MAP)) {
if (!(obj instanceof List)) {
throw new IOException("Attribute value should be of" +
" type List.");
}
maps = (List<CertificatePolicyMap>)obj;
} else {
throw new IOException("Attribute name not recognized by " +
"CertAttrSet:PolicyMappingsExtension.");
}
encodeThis();
}
/**
* Get the attribute value.
*/
public List<CertificatePolicyMap> get(String name) throws IOException {
if (name.equalsIgnoreCase(MAP)) {
return (maps);
} else {
throw new IOException("Attribute name not recognized by " +
"CertAttrSet:PolicyMappingsExtension.");
}
}
/**
* Delete the attribute value.
*/
public void delete(String name) throws IOException {
if (name.equalsIgnoreCase(MAP)) {
maps = null;
} else {
throw new IOException("Attribute name not recognized by " +
"CertAttrSet:PolicyMappingsExtension.");
}
encodeThis();
}
/**
* Return an enumeration of names of attributes existing within this
* attribute.
*/
public Enumeration<String> getElements () {
AttributeNameEnumeration elements = new AttributeNameEnumeration();
elements.addElement(MAP);
return elements.elements();
}
/**
* Return the name of this attribute.
*/
public String getName () {
return (NAME);
}
}

View File

@@ -0,0 +1,312 @@
/*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.io.OutputStream;
import java.security.cert.CertificateException;
import java.security.cert.CertificateParsingException;
import java.security.cert.CertificateExpiredException;
import java.security.cert.CertificateNotYetValidException;
import java.util.Date;
import java.util.Enumeration;
import java.util.Objects;
import sun.security.util.*;
/**
* This class defines the Private Key Usage Extension.
*
* <p>The Private Key Usage Period extension allows the certificate issuer
* to specify a different validity period for the private key than the
* certificate. This extension is intended for use with digital
* signature keys. This extension consists of two optional components
* notBefore and notAfter. The private key associated with the
* certificate should not be used to sign objects before or after the
* times specified by the two components, respectively.
*
* <pre>
* PrivateKeyUsagePeriod ::= SEQUENCE {
* notBefore [0] GeneralizedTime OPTIONAL,
* notAfter [1] GeneralizedTime OPTIONAL }
* </pre>
*
* @author Amit Kapoor
* @author Hemma Prafullchandra
* @see Extension
* @see CertAttrSet
*/
public class PrivateKeyUsageExtension extends Extension
implements CertAttrSet<String> {
/**
* Identifier for this attribute, to be used with the
* get, set, delete methods of Certificate, x509 type.
*/
public static final String IDENT = "x509.info.extensions.PrivateKeyUsage";
/**
* Sub attributes name for this CertAttrSet.
*/
public static final String NAME = "PrivateKeyUsage";
public static final String NOT_BEFORE = "not_before";
public static final String NOT_AFTER = "not_after";
// Private data members
private static final byte TAG_BEFORE = 0;
private static final byte TAG_AFTER = 1;
private Date notBefore = null;
private Date notAfter = null;
// Encode this extension value.
private void encodeThis() throws IOException {
if (notBefore == null && notAfter == null) {
this.extensionValue = null;
return;
}
DerOutputStream seq = new DerOutputStream();
DerOutputStream tagged = new DerOutputStream();
if (notBefore != null) {
DerOutputStream tmp = new DerOutputStream();
tmp.putGeneralizedTime(notBefore);
tagged.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT,
false, TAG_BEFORE), tmp);
}
if (notAfter != null) {
DerOutputStream tmp = new DerOutputStream();
tmp.putGeneralizedTime(notAfter);
tagged.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT,
false, TAG_AFTER), tmp);
}
seq.write(DerValue.tag_Sequence, tagged);
this.extensionValue = seq.toByteArray();
}
/**
* The default constructor for PrivateKeyUsageExtension.
*
* @param notBefore the date/time before which the private key
* should not be used.
* @param notAfter the date/time after which the private key
* should not be used.
*/
public PrivateKeyUsageExtension(Date notBefore, Date notAfter)
throws IOException {
this.notBefore = notBefore;
this.notAfter = notAfter;
this.extensionId = PKIXExtensions.PrivateKeyUsage_Id;
this.critical = false;
encodeThis();
}
/**
* Create the extension from the passed DER encoded value.
*
* @param critical true if the extension is to be treated as critical.
* @param value an array of DER encoded bytes of the actual value.
* @exception ClassCastException if value is not an array of bytes
* @exception CertificateException on certificate parsing errors.
* @exception IOException on error.
*/
public PrivateKeyUsageExtension(Boolean critical, Object value)
throws CertificateException, IOException {
this.extensionId = PKIXExtensions.PrivateKeyUsage_Id;
this.critical = critical.booleanValue();
this.extensionValue = (byte[]) value;
DerInputStream str = new DerInputStream(this.extensionValue);
DerValue[] seq = str.getSequence(2);
// NB. this is always encoded with the IMPLICIT tag
// The checks only make sense if we assume implicit tagging,
// with explicit tagging the form is always constructed.
for (int i = 0; i < seq.length; i++) {
DerValue opt = seq[i];
if (opt.isContextSpecific(TAG_BEFORE) &&
!opt.isConstructed()) {
if (notBefore != null) {
throw new CertificateParsingException(
"Duplicate notBefore in PrivateKeyUsage.");
}
opt.resetTag(DerValue.tag_GeneralizedTime);
str = new DerInputStream(opt.toByteArray());
notBefore = str.getGeneralizedTime();
} else if (opt.isContextSpecific(TAG_AFTER) &&
!opt.isConstructed()) {
if (notAfter != null) {
throw new CertificateParsingException(
"Duplicate notAfter in PrivateKeyUsage.");
}
opt.resetTag(DerValue.tag_GeneralizedTime);
str = new DerInputStream(opt.toByteArray());
notAfter = str.getGeneralizedTime();
} else
throw new IOException("Invalid encoding of " +
"PrivateKeyUsageExtension");
}
}
/**
* Return the printable string.
*/
public String toString() {
return(super.toString() +
"PrivateKeyUsage: [\n" +
((notBefore == null) ? "" : "From: " + notBefore.toString() + ", ")
+ ((notAfter == null) ? "" : "To: " + notAfter.toString())
+ "]\n");
}
/**
* Verify that that the current time is within the validity period.
*
* @exception CertificateExpiredException if the certificate has expired.
* @exception CertificateNotYetValidException if the certificate is not
* yet valid.
*/
public void valid()
throws CertificateNotYetValidException, CertificateExpiredException {
Date now = new Date();
valid(now);
}
/**
* Verify that that the passed time is within the validity period.
*
* @exception CertificateExpiredException if the certificate has expired
* with respect to the <code>Date</code> supplied.
* @exception CertificateNotYetValidException if the certificate is not
* yet valid with respect to the <code>Date</code> supplied.
*
*/
public void valid(Date now)
throws CertificateNotYetValidException, CertificateExpiredException {
Objects.requireNonNull(now);
/*
* we use the internal Dates rather than the passed in Date
* because someone could override the Date methods after()
* and before() to do something entirely different.
*/
if (notBefore != null && notBefore.after(now)) {
throw new CertificateNotYetValidException("NotBefore: " +
notBefore.toString());
}
if (notAfter != null && notAfter.before(now)) {
throw new CertificateExpiredException("NotAfter: " +
notAfter.toString());
}
}
/**
* Write the extension to the OutputStream.
*
* @param out the OutputStream to write the extension to.
* @exception IOException on encoding errors.
*/
public void encode(OutputStream out) throws IOException {
DerOutputStream tmp = new DerOutputStream();
if (extensionValue == null) {
extensionId = PKIXExtensions.PrivateKeyUsage_Id;
critical = false;
encodeThis();
}
super.encode(tmp);
out.write(tmp.toByteArray());
}
/**
* Set the attribute value.
* @exception CertificateException on attribute handling errors.
*/
public void set(String name, Object obj)
throws CertificateException, IOException {
if (!(obj instanceof Date)) {
throw new CertificateException("Attribute must be of type Date.");
}
if (name.equalsIgnoreCase(NOT_BEFORE)) {
notBefore = (Date)obj;
} else if (name.equalsIgnoreCase(NOT_AFTER)) {
notAfter = (Date)obj;
} else {
throw new CertificateException("Attribute name not recognized by"
+ " CertAttrSet:PrivateKeyUsage.");
}
encodeThis();
}
/**
* Get the attribute value.
* @exception CertificateException on attribute handling errors.
*/
public Date get(String name) throws CertificateException {
if (name.equalsIgnoreCase(NOT_BEFORE)) {
return (new Date(notBefore.getTime()));
} else if (name.equalsIgnoreCase(NOT_AFTER)) {
return (new Date(notAfter.getTime()));
} else {
throw new CertificateException("Attribute name not recognized by"
+ " CertAttrSet:PrivateKeyUsage.");
}
}
/**
* Delete the attribute value.
* @exception CertificateException on attribute handling errors.
*/
public void delete(String name) throws CertificateException, IOException {
if (name.equalsIgnoreCase(NOT_BEFORE)) {
notBefore = null;
} else if (name.equalsIgnoreCase(NOT_AFTER)) {
notAfter = null;
} else {
throw new CertificateException("Attribute name not recognized by"
+ " CertAttrSet:PrivateKeyUsage.");
}
encodeThis();
}
/**
* Return an enumeration of names of attributes existing within this
* attribute.
*/
public Enumeration<String> getElements() {
AttributeNameEnumeration elements = new AttributeNameEnumeration();
elements.addElement(NOT_BEFORE);
elements.addElement(NOT_AFTER);
return(elements.elements());
}
/**
* Return the name of this attribute.
*/
public String getName() {
return(NAME);
}
}

View File

@@ -0,0 +1,496 @@
/*
* Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.io.StringReader;
import java.util.Arrays;
import java.util.StringJoiner;
import java.util.*;
import sun.security.util.*;
/**
* RDNs are a set of {attribute = value} assertions. Some of those
* attributes are "distinguished" (unique w/in context). Order is
* never relevant.
*
* Some X.500 names include only a single distinguished attribute
* per RDN. This style is currently common.
*
* Note that DER-encoded RDNs sort AVAs by assertion OID ... so that
* when we parse this data we don't have to worry about canonicalizing
* it, but we'll need to sort them when we expose the RDN class more.
* <p>
* The ASN.1 for RDNs is:
* <pre>
* RelativeDistinguishedName ::=
* SET OF AttributeTypeAndValue
*
* AttributeTypeAndValue ::= SEQUENCE {
* type AttributeType,
* value AttributeValue }
*
* AttributeType ::= OBJECT IDENTIFIER
*
* AttributeValue ::= ANY DEFINED BY AttributeType
* </pre>
*
* Note that instances of this class are immutable.
*
*/
public class RDN {
// currently not private, accessed directly from X500Name
final AVA[] assertion;
// cached immutable List of the AVAs
private volatile List<AVA> avaList;
// cache canonical String form
private volatile String canonicalString;
/**
* Constructs an RDN from its printable representation.
*
* An RDN may consist of one or multiple Attribute Value Assertions (AVAs),
* using '+' as a separator.
* If the '+' should be considered part of an AVA value, it must be
* preceded by '\'.
*
* @param name String form of RDN
* @throws IOException on parsing error
*/
public RDN(String name) throws IOException {
this(name, Collections.<String, String>emptyMap());
}
/**
* Constructs an RDN from its printable representation.
*
* An RDN may consist of one or multiple Attribute Value Assertions (AVAs),
* using '+' as a separator.
* If the '+' should be considered part of an AVA value, it must be
* preceded by '\'.
*
* @param name String form of RDN
* @param keyword an additional mapping of keywords to OIDs
* @throws IOException on parsing error
*/
public RDN(String name, Map<String, String> keywordMap) throws IOException {
int quoteCount = 0;
int searchOffset = 0;
int avaOffset = 0;
List<AVA> avaVec = new ArrayList<AVA>(3);
int nextPlus = name.indexOf('+');
while (nextPlus >= 0) {
quoteCount += X500Name.countQuotes(name, searchOffset, nextPlus);
/*
* We have encountered an AVA delimiter (plus sign).
* If the plus sign in the RDN under consideration is
* preceded by a backslash (escape), or by a double quote, it
* is part of the AVA. Otherwise, it is used as a separator, to
* delimit the AVA under consideration from any subsequent AVAs.
*/
if (nextPlus > 0 && name.charAt(nextPlus - 1) != '\\'
&& quoteCount != 1) {
/*
* Plus sign is a separator
*/
String avaString = name.substring(avaOffset, nextPlus);
if (avaString.length() == 0) {
throw new IOException("empty AVA in RDN \"" + name + "\"");
}
// Parse AVA, and store it in vector
AVA ava = new AVA(new StringReader(avaString), keywordMap);
avaVec.add(ava);
// Increase the offset
avaOffset = nextPlus + 1;
// Set quote counter back to zero
quoteCount = 0;
}
searchOffset = nextPlus + 1;
nextPlus = name.indexOf('+', searchOffset);
}
// parse last or only AVA
String avaString = name.substring(avaOffset);
if (avaString.length() == 0) {
throw new IOException("empty AVA in RDN \"" + name + "\"");
}
AVA ava = new AVA(new StringReader(avaString), keywordMap);
avaVec.add(ava);
assertion = avaVec.toArray(new AVA[avaVec.size()]);
}
/*
* Constructs an RDN from its printable representation.
*
* An RDN may consist of one or multiple Attribute Value Assertions (AVAs),
* using '+' as a separator.
* If the '+' should be considered part of an AVA value, it must be
* preceded by '\'.
*
* @param name String form of RDN
* @throws IOException on parsing error
*/
RDN(String name, String format) throws IOException {
this(name, format, Collections.<String, String>emptyMap());
}
/*
* Constructs an RDN from its printable representation.
*
* An RDN may consist of one or multiple Attribute Value Assertions (AVAs),
* using '+' as a separator.
* If the '+' should be considered part of an AVA value, it must be
* preceded by '\'.
*
* @param name String form of RDN
* @param keyword an additional mapping of keywords to OIDs
* @throws IOException on parsing error
*/
RDN(String name, String format, Map<String, String> keywordMap)
throws IOException {
if (format.equalsIgnoreCase("RFC2253") == false) {
throw new IOException("Unsupported format " + format);
}
int searchOffset = 0;
int avaOffset = 0;
List<AVA> avaVec = new ArrayList<AVA>(3);
int nextPlus = name.indexOf('+');
while (nextPlus >= 0) {
/*
* We have encountered an AVA delimiter (plus sign).
* If the plus sign in the RDN under consideration is
* preceded by a backslash (escape), or by a double quote, it
* is part of the AVA. Otherwise, it is used as a separator, to
* delimit the AVA under consideration from any subsequent AVAs.
*/
if (nextPlus > 0 && name.charAt(nextPlus - 1) != '\\' ) {
/*
* Plus sign is a separator
*/
String avaString = name.substring(avaOffset, nextPlus);
if (avaString.length() == 0) {
throw new IOException("empty AVA in RDN \"" + name + "\"");
}
// Parse AVA, and store it in vector
AVA ava = new AVA
(new StringReader(avaString), AVA.RFC2253, keywordMap);
avaVec.add(ava);
// Increase the offset
avaOffset = nextPlus + 1;
}
searchOffset = nextPlus + 1;
nextPlus = name.indexOf('+', searchOffset);
}
// parse last or only AVA
String avaString = name.substring(avaOffset);
if (avaString.length() == 0) {
throw new IOException("empty AVA in RDN \"" + name + "\"");
}
AVA ava = new AVA(new StringReader(avaString), AVA.RFC2253, keywordMap);
avaVec.add(ava);
assertion = avaVec.toArray(new AVA[avaVec.size()]);
}
/*
* Constructs an RDN from an ASN.1 encoded value. The encoding
* of the name in the stream uses DER (a BER/1 subset).
*
* @param value a DER-encoded value holding an RDN.
* @throws IOException on parsing error.
*/
RDN(DerValue rdn) throws IOException {
if (rdn.tag != DerValue.tag_Set) {
throw new IOException("X500 RDN");
}
DerInputStream dis = new DerInputStream(rdn.toByteArray());
DerValue[] avaset = dis.getSet(5);
assertion = new AVA[avaset.length];
for (int i = 0; i < avaset.length; i++) {
assertion[i] = new AVA(avaset[i]);
}
}
/*
* Creates an empty RDN with slots for specified
* number of AVAs.
*
* @param i number of AVAs to be in RDN
*/
RDN(int i) { assertion = new AVA[i]; }
public RDN(AVA ava) {
if (ava == null) {
throw new NullPointerException();
}
assertion = new AVA[] { ava };
}
public RDN(AVA[] avas) {
assertion = avas.clone();
for (int i = 0; i < assertion.length; i++) {
if (assertion[i] == null) {
throw new NullPointerException();
}
}
}
/**
* Return an immutable List of the AVAs in this RDN.
*/
public List<AVA> avas() {
List<AVA> list = avaList;
if (list == null) {
list = Collections.unmodifiableList(Arrays.asList(assertion));
avaList = list;
}
return list;
}
/**
* Return the number of AVAs in this RDN.
*/
public int size() {
return assertion.length;
}
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof RDN == false) {
return false;
}
RDN other = (RDN)obj;
if (this.assertion.length != other.assertion.length) {
return false;
}
String thisCanon = this.toRFC2253String(true);
String otherCanon = other.toRFC2253String(true);
return thisCanon.equals(otherCanon);
}
/*
* Calculates a hash code value for the object. Objects
* which are equal will also have the same hashcode.
*
* @returns int hashCode value
*/
public int hashCode() {
return toRFC2253String(true).hashCode();
}
/*
* return specified attribute value from RDN
*
* @params oid ObjectIdentifier of attribute to be found
* @returns DerValue of attribute value; null if attribute does not exist
*/
DerValue findAttribute(ObjectIdentifier oid) {
for (int i = 0; i < assertion.length; i++) {
if (assertion[i].oid.equals((Object)oid)) {
return assertion[i].value;
}
}
return null;
}
/*
* Encode the RDN in DER-encoded form.
*
* @param out DerOutputStream to which RDN is to be written
* @throws IOException on error
*/
void encode(DerOutputStream out) throws IOException {
out.putOrderedSetOf(DerValue.tag_Set, assertion);
}
/*
* Returns a printable form of this RDN, using RFC 1779 style catenation
* of attribute/value assertions, and emitting attribute type keywords
* from RFCs 1779, 2253, and 5280.
*/
public String toString() {
if (assertion.length == 1) {
return assertion[0].toString();
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < assertion.length; i++) {
if (i != 0) {
sb.append(" + ");
}
sb.append(assertion[i].toString());
}
return sb.toString();
}
/*
* Returns a printable form of this RDN using the algorithm defined in
* RFC 1779. Only RFC 1779 attribute type keywords are emitted.
*/
public String toRFC1779String() {
return toRFC1779String(Collections.<String, String>emptyMap());
}
/*
* Returns a printable form of this RDN using the algorithm defined in
* RFC 1779. RFC 1779 attribute type keywords are emitted, as well
* as keywords contained in the OID/keyword map.
*/
public String toRFC1779String(Map<String, String> oidMap) {
if (assertion.length == 1) {
return assertion[0].toRFC1779String(oidMap);
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < assertion.length; i++) {
if (i != 0) {
sb.append(" + ");
}
sb.append(assertion[i].toRFC1779String(oidMap));
}
return sb.toString();
}
/*
* Returns a printable form of this RDN using the algorithm defined in
* RFC 2253. Only RFC 2253 attribute type keywords are emitted.
*/
public String toRFC2253String() {
return toRFC2253StringInternal
(false, Collections.<String, String>emptyMap());
}
/*
* Returns a printable form of this RDN using the algorithm defined in
* RFC 2253. RFC 2253 attribute type keywords are emitted, as well as
* keywords contained in the OID/keyword map.
*/
public String toRFC2253String(Map<String, String> oidMap) {
return toRFC2253StringInternal(false, oidMap);
}
/*
* Returns a printable form of this RDN using the algorithm defined in
* RFC 2253. Only RFC 2253 attribute type keywords are emitted.
* If canonical is true, then additional canonicalizations
* documented in X500Principal.getName are performed.
*/
public String toRFC2253String(boolean canonical) {
if (canonical == false) {
return toRFC2253StringInternal
(false, Collections.<String, String>emptyMap());
}
String c = canonicalString;
if (c == null) {
c = toRFC2253StringInternal
(true, Collections.<String, String>emptyMap());
canonicalString = c;
}
return c;
}
private String toRFC2253StringInternal
(boolean canonical, Map<String, String> oidMap) {
/*
* Section 2.2: When converting from an ASN.1 RelativeDistinguishedName
* to a string, the output consists of the string encodings of each
* AttributeTypeAndValue (according to 2.3), in any order.
*
* Where there is a multi-valued RDN, the outputs from adjoining
* AttributeTypeAndValues are separated by a plus ('+' ASCII 43)
* character.
*/
// normally, an RDN only contains one AVA
if (assertion.length == 1) {
return canonical ? assertion[0].toRFC2253CanonicalString() :
assertion[0].toRFC2253String(oidMap);
}
AVA[] toOutput = assertion;
if (canonical) {
// order the string type AVA's alphabetically,
// followed by the oid type AVA's numerically
toOutput = assertion.clone();
Arrays.sort(toOutput, AVAComparator.getInstance());
}
StringJoiner sj = new StringJoiner("+");
for (AVA ava : toOutput) {
sj.add(canonical ? ava.toRFC2253CanonicalString()
: ava.toRFC2253String(oidMap));
}
return sj.toString();
}
}
class AVAComparator implements Comparator<AVA> {
private static final Comparator<AVA> INSTANCE = new AVAComparator();
private AVAComparator() {
// empty
}
static Comparator<AVA> getInstance() {
return INSTANCE;
}
/**
* AVA's containing a standard keyword are ordered alphabetically,
* followed by AVA's containing an OID keyword, ordered numerically
*/
public int compare(AVA a1, AVA a2) {
boolean a1Has2253 = a1.hasRFC2253Keyword();
boolean a2Has2253 = a2.hasRFC2253Keyword();
if (a1Has2253 == a2Has2253) {
return a1.toRFC2253CanonicalString().compareTo
(a2.toRFC2253CanonicalString());
} else {
if (a1Has2253) {
return -1;
} else {
return 1;
}
}
}
}

View File

@@ -0,0 +1,256 @@
/*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.util.Locale;
import sun.security.util.*;
/**
* This class implements the RFC822Name as required by the GeneralNames
* ASN.1 object.
*
* @author Amit Kapoor
* @author Hemma Prafullchandra
* @see GeneralName
* @see GeneralNames
* @see GeneralNameInterface
*/
public class RFC822Name implements GeneralNameInterface
{
private String name;
/**
* Create the RFC822Name object from the passed encoded Der value.
*
* @param derValue the encoded DER RFC822Name.
* @exception IOException on error.
*/
public RFC822Name(DerValue derValue) throws IOException {
name = derValue.getIA5String();
parseName(name);
}
/**
* Create the RFC822Name object with the specified name.
*
* @param name the RFC822Name.
* @throws IOException on invalid input name
*/
public RFC822Name(String name) throws IOException {
parseName(name);
this.name = name;
}
/**
* Parse an RFC822Name string to see if it is a valid
* addr-spec according to IETF RFC822 and RFC2459:
* [local-part@]domain
* <p>
* local-part@ could be empty for an RFC822Name NameConstraint,
* but the domain at least must be non-empty. Case is not
* significant.
*
* @param name the RFC822Name string
* @throws IOException if name is not valid
*/
public void parseName(String name) throws IOException {
if (name == null || name.length() == 0) {
throw new IOException("RFC822Name may not be null or empty");
}
// See if domain is a valid domain name
String domain = name.substring(name.indexOf('@')+1);
if (domain.length() == 0) {
throw new IOException("RFC822Name may not end with @");
} else {
//An RFC822 NameConstraint could start with a ., although
//a DNSName may not
if (domain.startsWith(".")) {
if (domain.length() == 1)
throw new IOException("RFC822Name domain may not be just .");
}
}
}
/**
* Return the type of the GeneralName.
*/
public int getType() {
return (GeneralNameInterface.NAME_RFC822);
}
/**
* Return the actual name value of the GeneralName.
*/
public String getName() {
return name;
}
/**
* Encode the RFC822 name into the DerOutputStream.
*
* @param out the DER stream to encode the RFC822Name to.
* @exception IOException on encoding errors.
*/
public void encode(DerOutputStream out) throws IOException {
out.putIA5String(name);
}
/**
* Convert the name into user readable string.
*/
public String toString() {
return ("RFC822Name: " + name);
}
/**
* Compares this name with another, for equality.
*
* @return true iff the names are equivalent
* according to RFC2459.
*/
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!(obj instanceof RFC822Name))
return false;
RFC822Name other = (RFC822Name)obj;
// RFC2459 mandates that these names are
// not case-sensitive
return name.equalsIgnoreCase(other.name);
}
/**
* Returns the hash code value for this object.
*
* @return a hash code value for this object.
*/
public int hashCode() {
return name.toUpperCase(Locale.ENGLISH).hashCode();
}
/**
* Return constraint type:<ul>
* <li>NAME_DIFF_TYPE = -1: input name is different type from name (i.e. does not constrain)
* <li>NAME_MATCH = 0: input name matches name
* <li>NAME_NARROWS = 1: input name narrows name
* <li>NAME_WIDENS = 2: input name widens name
* <li>NAME_SAME_TYPE = 3: input name does not match or narrow name, but is same type
* </ul>. These results are used in checking NameConstraints during
* certification path verification.
* <p>
* [RFC2459] When the subjectAltName extension contains an Internet mail address,
* the address MUST be included as an rfc822Name. The format of an
* rfc822Name is an "addr-spec" as defined in RFC 822 [RFC 822]. An
* addr-spec has the form "local-part@domain". Note that an addr-spec
* has no phrase (such as a common name) before it, has no comment (text
* surrounded in parentheses) after it, and is not surrounded by "&lt;" and
* "&gt;". Note that while upper and lower case letters are allowed in an
* RFC 822 addr-spec, no significance is attached to the case.
* <p>
* @param inputName to be checked for being constrained
* @returns constraint type above
* @throws UnsupportedOperationException if name is not exact match, but narrowing and widening are
* not supported for this name type.
*/
public int constrains(GeneralNameInterface inputName) throws UnsupportedOperationException {
int constraintType;
if (inputName == null)
constraintType = NAME_DIFF_TYPE;
else if (inputName.getType() != (GeneralNameInterface.NAME_RFC822)) {
constraintType = NAME_DIFF_TYPE;
} else {
//RFC2459 specifies that case is not significant in RFC822Names
String inName =
(((RFC822Name)inputName).getName()).toLowerCase(Locale.ENGLISH);
String thisName = name.toLowerCase(Locale.ENGLISH);
if (inName.equals(thisName)) {
constraintType = NAME_MATCH;
} else if (thisName.endsWith(inName)) {
/* if both names contain @, then they had to match exactly */
if (inName.indexOf('@') != -1) {
constraintType = NAME_SAME_TYPE;
} else if (inName.startsWith(".")) {
constraintType = NAME_WIDENS;
} else {
int inNdx = thisName.lastIndexOf(inName);
if (thisName.charAt(inNdx-1) == '@' ) {
constraintType = NAME_WIDENS;
} else {
constraintType = NAME_SAME_TYPE;
}
}
} else if (inName.endsWith(thisName)) {
/* if thisName contains @, then they had to match exactly */
if (thisName.indexOf('@') != -1) {
constraintType = NAME_SAME_TYPE;
} else if (thisName.startsWith(".")) {
constraintType = NAME_NARROWS;
} else {
int ndx = inName.lastIndexOf(thisName);
if (inName.charAt(ndx-1) == '@') {
constraintType = NAME_NARROWS;
} else {
constraintType = NAME_SAME_TYPE;
}
}
} else {
constraintType = NAME_SAME_TYPE;
}
}
return constraintType;
}
/**
* Return subtree depth of this name for purposes of determining
* NameConstraints minimum and maximum bounds.
*
* @returns distance of name from root
* @throws UnsupportedOperationException if not supported for this name type
*/
public int subtreeDepth() throws UnsupportedOperationException {
String subtree=name;
int i=1;
/* strip off name@ portion */
int atNdx = subtree.lastIndexOf('@');
if (atNdx >= 0) {
i++;
subtree=subtree.substring(atNdx+1);
}
/* count dots in DNSName, adding one if DNSName preceded by @ */
for (; subtree.lastIndexOf('.') >= 0; i++) {
subtree=subtree.substring(0,subtree.lastIndexOf('.'));
}
return i;
}
}

View File

@@ -0,0 +1,258 @@
/*
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import sun.security.util.*;
/**
* Represent the CRL Reason Flags.
*
* <p>This extension, if present, defines the identifies
* the reason for the certificate revocation.
* <p>The ASN.1 syntax for this is:
* <pre>
* ReasonFlags ::= BIT STRING {
* unused (0),
* keyCompromise (1),
* cACompromise (2),
* affiliationChanged (3),
* superseded (4),
* cessationOfOperation (5),
* certificateHold (6),
* privilegeWithdrawn (7),
* aACompromise (8) }
* </pre>
*
* @author Hemma Prafullchandra
*/
public class ReasonFlags {
/**
* Reasons
*/
public static final String UNUSED = "unused";
public static final String KEY_COMPROMISE = "key_compromise";
public static final String CA_COMPROMISE = "ca_compromise";
public static final String AFFILIATION_CHANGED = "affiliation_changed";
public static final String SUPERSEDED = "superseded";
public static final String CESSATION_OF_OPERATION
= "cessation_of_operation";
public static final String CERTIFICATE_HOLD = "certificate_hold";
public static final String PRIVILEGE_WITHDRAWN = "privilege_withdrawn";
public static final String AA_COMPROMISE = "aa_compromise";
private final static String[] NAMES = {
UNUSED,
KEY_COMPROMISE,
CA_COMPROMISE,
AFFILIATION_CHANGED,
SUPERSEDED,
CESSATION_OF_OPERATION,
CERTIFICATE_HOLD,
PRIVILEGE_WITHDRAWN,
AA_COMPROMISE,
};
private static int name2Index(String name) throws IOException {
for( int i=0; i<NAMES.length; i++ ) {
if( NAMES[i].equalsIgnoreCase(name) ) {
return i;
}
}
throw new IOException("Name not recognized by ReasonFlags");
}
// Private data members
private boolean[] bitString;
/**
* Check if bit is set.
*
* @param position the position in the bit string to check.
*/
private boolean isSet(int position) {
return (position < bitString.length) &&
bitString[position];
}
/**
* Set the bit at the specified position.
*/
private void set(int position, boolean val) {
// enlarge bitString if necessary
if (position >= bitString.length) {
boolean[] tmp = new boolean[position+1];
System.arraycopy(bitString, 0, tmp, 0, bitString.length);
bitString = tmp;
}
bitString[position] = val;
}
/**
* Create a ReasonFlags with the passed bit settings.
*
* @param reasons the bits to be set for the ReasonFlags.
*/
public ReasonFlags(byte[] reasons) {
bitString = new BitArray(reasons.length*8, reasons).toBooleanArray();
}
/**
* Create a ReasonFlags with the passed bit settings.
*
* @param reasons the bits to be set for the ReasonFlags.
*/
public ReasonFlags(boolean[] reasons) {
this.bitString = reasons;
}
/**
* Create a ReasonFlags with the passed bit settings.
*
* @param reasons the bits to be set for the ReasonFlags.
*/
public ReasonFlags(BitArray reasons) {
this.bitString = reasons.toBooleanArray();
}
/**
* Create the object from the passed DER encoded value.
*
* @param in the DerInputStream to read the ReasonFlags from.
* @exception IOException on decoding errors.
*/
public ReasonFlags(DerInputStream in) throws IOException {
DerValue derVal = in.getDerValue();
this.bitString = derVal.getUnalignedBitString(true).toBooleanArray();
}
/**
* Create the object from the passed DER encoded value.
*
* @param derVal the DerValue decoded from the stream.
* @exception IOException on decoding errors.
*/
public ReasonFlags(DerValue derVal) throws IOException {
this.bitString = derVal.getUnalignedBitString(true).toBooleanArray();
}
/**
* Returns the reason flags as a boolean array.
*/
public boolean[] getFlags() {
return bitString;
}
/**
* Set the attribute value.
*/
public void set(String name, Object obj) throws IOException {
if (!(obj instanceof Boolean)) {
throw new IOException("Attribute must be of type Boolean.");
}
boolean val = ((Boolean)obj).booleanValue();
set(name2Index(name), val);
}
/**
* Get the attribute value.
*/
public Object get(String name) throws IOException {
return Boolean.valueOf(isSet(name2Index(name)));
}
/**
* Delete the attribute value.
*/
public void delete(String name) throws IOException {
set(name, Boolean.FALSE);
}
/**
* Returns a printable representation of the ReasonFlags.
*/
public String toString() {
StringBuilder sb = new StringBuilder("Reason Flags [\n");
if (isSet(0)) {
sb.append(" Unused\n");
}
if (isSet(1)) {
sb.append(" Key Compromise\n");
}
if (isSet(2)) {
sb.append(" CA Compromise\n");
}
if (isSet(3)) {
sb.append(" Affiliation_Changed\n");
}
if (isSet(4)) {
sb.append(" Superseded\n");
}
if (isSet(5)) {
sb.append(" Cessation Of Operation\n");
}
if (isSet(6)) {
sb.append(" Certificate Hold\n");
}
if (isSet(7)) {
sb.append(" Privilege Withdrawn\n");
}
if (isSet(8)) {
sb.append(" AA Compromise\n");
}
sb.append("]\n");
return sb.toString();
}
/**
* Write the extension to the DerOutputStream.
*
* @param out the DerOutputStream to write the extension to.
* @exception IOException on encoding errors.
*/
public void encode(DerOutputStream out) throws IOException {
out.putTruncatedUnalignedBitString(new BitArray(this.bitString));
}
/**
* Return an enumeration of names of attributes existing within this
* attribute.
*/
public Enumeration<String> getElements () {
AttributeNameEnumeration elements = new AttributeNameEnumeration();
for( int i=0; i<NAMES.length; i++ ) {
elements.addElement(NAMES[i]);
}
return (elements.elements());
}
}

View File

@@ -0,0 +1,123 @@
/*
* Copyright (c) 1997, 2002, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import sun.security.util.*;
/**
* This class defines the SerialNumber class used by certificates.
*
* @author Amit Kapoor
* @author Hemma Prafullchandra
*/
public class SerialNumber {
private BigInteger serialNum;
// Construct the class from the DerValue
private void construct(DerValue derVal) throws IOException {
serialNum = derVal.getBigInteger();
if (derVal.data.available() != 0) {
throw new IOException("Excess SerialNumber data");
}
}
/**
* The default constructor for this class using BigInteger.
*
* @param num the BigInteger number used to create the serial number.
*/
public SerialNumber(BigInteger num) {
serialNum = num;
}
/**
* The default constructor for this class using int.
*
* @param num the BigInteger number used to create the serial number.
*/
public SerialNumber(int num) {
serialNum = BigInteger.valueOf(num);
}
/**
* Create the object, decoding the values from the passed DER stream.
*
* @param in the DerInputStream to read the SerialNumber from.
* @exception IOException on decoding errors.
*/
public SerialNumber(DerInputStream in) throws IOException {
DerValue derVal = in.getDerValue();
construct(derVal);
}
/**
* Create the object, decoding the values from the passed DerValue.
*
* @param val the DerValue to read the SerialNumber from.
* @exception IOException on decoding errors.
*/
public SerialNumber(DerValue val) throws IOException {
construct(val);
}
/**
* Create the object, decoding the values from the passed stream.
*
* @param in the InputStream to read the SerialNumber from.
* @exception IOException on decoding errors.
*/
public SerialNumber(InputStream in) throws IOException {
DerValue derVal = new DerValue(in);
construct(derVal);
}
/**
* Return the SerialNumber as user readable string.
*/
public String toString() {
return ("SerialNumber: [" + Debug.toHexString(serialNum) + "]");
}
/**
* Encode the SerialNumber in DER form to the stream.
*
* @param out the DerOutputStream to marshal the contents to.
* @exception IOException on errors.
*/
public void encode(DerOutputStream out) throws IOException {
out.putInteger(serialNum);
}
/**
* Return the serial number.
*/
public BigInteger getNumber() {
return serialNum;
}
}

View File

@@ -0,0 +1,237 @@
/*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Enumeration;
import sun.security.util.*;
/**
* This represents the Subject Alternative Name Extension.
*
* This extension, if present, allows the subject to specify multiple
* alternative names.
*
* <p>Extensions are represented as a sequence of the extension identifier
* (Object Identifier), a boolean flag stating whether the extension is to
* be treated as being critical and the extension value itself (this is again
* a DER encoding of the extension value).
* <p>
* The ASN.1 syntax for this is:
* <pre>
* SubjectAltName ::= GeneralNames
* GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
* </pre>
* @author Amit Kapoor
* @author Hemma Prafullchandra
* @see Extension
* @see CertAttrSet
*/
public class SubjectAlternativeNameExtension extends Extension
implements CertAttrSet<String> {
/**
* Identifier for this attribute, to be used with the
* get, set, delete methods of Certificate, x509 type.
*/
public static final String IDENT =
"x509.info.extensions.SubjectAlternativeName";
/**
* Attribute names.
*/
public static final String NAME = "SubjectAlternativeName";
public static final String SUBJECT_NAME = "subject_name";
// private data members
GeneralNames names = null;
// Encode this extension
private void encodeThis() throws IOException {
if (names == null || names.isEmpty()) {
this.extensionValue = null;
return;
}
DerOutputStream os = new DerOutputStream();
names.encode(os);
this.extensionValue = os.toByteArray();
}
/**
* Create a SubjectAlternativeNameExtension with the passed GeneralNames.
* The extension is marked non-critical.
*
* @param names the GeneralNames for the subject.
* @exception IOException on error.
*/
public SubjectAlternativeNameExtension(GeneralNames names)
throws IOException {
this(Boolean.FALSE, names);
}
/**
* Create a SubjectAlternativeNameExtension with the specified
* criticality and GeneralNames.
*
* @param critical true if the extension is to be treated as critical.
* @param names the GeneralNames for the subject.
* @exception IOException on error.
*/
public SubjectAlternativeNameExtension(Boolean critical, GeneralNames names)
throws IOException {
this.names = names;
this.extensionId = PKIXExtensions.SubjectAlternativeName_Id;
this.critical = critical.booleanValue();
encodeThis();
}
/**
* Create a default SubjectAlternativeNameExtension. The extension
* is marked non-critical.
*/
public SubjectAlternativeNameExtension() {
extensionId = PKIXExtensions.SubjectAlternativeName_Id;
critical = false;
names = new GeneralNames();
}
/**
* Create the extension from the passed DER encoded value.
*
* @param critical true if the extension is to be treated as critical.
* @param value an array of DER encoded bytes of the actual value.
* @exception ClassCastException if value is not an array of bytes
* @exception IOException on error.
*/
public SubjectAlternativeNameExtension(Boolean critical, Object value)
throws IOException {
this.extensionId = PKIXExtensions.SubjectAlternativeName_Id;
this.critical = critical.booleanValue();
this.extensionValue = (byte[]) value;
DerValue val = new DerValue(this.extensionValue);
if (val.data == null) {
names = new GeneralNames();
return;
}
names = new GeneralNames(val);
}
/**
* Returns a printable representation of the SubjectAlternativeName.
*/
public String toString() {
String result = super.toString() + "SubjectAlternativeName [\n";
if(names == null) {
result += " null\n";
} else {
for(GeneralName name: names.names()) {
result += " "+name+"\n";
}
}
result += "]\n";
return result;
}
/**
* Write the extension to the OutputStream.
*
* @param out the OutputStream to write the extension to.
* @exception IOException on encoding errors.
*/
public void encode(OutputStream out) throws IOException {
DerOutputStream tmp = new DerOutputStream();
if (extensionValue == null) {
extensionId = PKIXExtensions.SubjectAlternativeName_Id;
critical = false;
encodeThis();
}
super.encode(tmp);
out.write(tmp.toByteArray());
}
/**
* Set the attribute value.
*/
public void set(String name, Object obj) throws IOException {
if (name.equalsIgnoreCase(SUBJECT_NAME)) {
if (!(obj instanceof GeneralNames)) {
throw new IOException("Attribute value should be of " +
"type GeneralNames.");
}
names = (GeneralNames)obj;
} else {
throw new IOException("Attribute name not recognized by " +
"CertAttrSet:SubjectAlternativeName.");
}
encodeThis();
}
/**
* Get the attribute value.
*/
public GeneralNames get(String name) throws IOException {
if (name.equalsIgnoreCase(SUBJECT_NAME)) {
return (names);
} else {
throw new IOException("Attribute name not recognized by " +
"CertAttrSet:SubjectAlternativeName.");
}
}
/**
* Delete the attribute value.
*/
public void delete(String name) throws IOException {
if (name.equalsIgnoreCase(SUBJECT_NAME)) {
names = null;
} else {
throw new IOException("Attribute name not recognized by " +
"CertAttrSet:SubjectAlternativeName.");
}
encodeThis();
}
/**
* Return an enumeration of names of attributes existing within this
* attribute.
*/
public Enumeration<String> getElements() {
AttributeNameEnumeration elements = new AttributeNameEnumeration();
elements.addElement(SUBJECT_NAME);
return (elements.elements());
}
/**
* Return the name of this attribute.
*/
public String getName() {
return (NAME);
}
}

View File

@@ -0,0 +1,247 @@
/*
* Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Collections;
import java.util.*;
import sun.security.util.DerOutputStream;
import sun.security.util.DerValue;
/**
* The Subject Information Access Extension (OID = 1.3.6.1.5.5.7.1.11).
* <p>
* The subject information access extension indicates how to access
* information and services for the subject of the certificate in which
* the extension appears. When the subject is a CA, information and
* services may include certificate validation services and CA policy
* data. When the subject is an end entity, the information describes
* the type of services offered and how to access them. In this case,
* the contents of this extension are defined in the protocol
* specifications for the supported services. This extension may be
* included in end entity or CA certificates. Conforming CAs MUST mark
* this extension as non-critical.
* <p>
* This extension is defined in <a href="http://tools.ietf.org/html/rfc5280">
* Internet X.509 PKI Certificate and Certificate Revocation List
* (CRL) Profile</a>. The profile permits
* the extension to be included in end-entity or CA certificates,
* and it must be marked as non-critical. Its ASN.1 definition is as follows:
* <pre>
* id-pe-subjectInfoAccess OBJECT IDENTIFIER ::= { id-pe 11 }
*
* SubjectInfoAccessSyntax ::=
* SEQUENCE SIZE (1..MAX) OF AccessDescription
*
* AccessDescription ::= SEQUENCE {
* accessMethod OBJECT IDENTIFIER,
* accessLocation GeneralName }
* </pre>
* <p>
* @see Extension
* @see CertAttrSet
*/
public class SubjectInfoAccessExtension extends Extension
implements CertAttrSet<String> {
/**
* Identifier for this attribute, to be used with the
* get, set, delete methods of Certificate, x509 type.
*/
public static final String IDENT =
"x509.info.extensions.SubjectInfoAccess";
/**
* Attribute name.
*/
public static final String NAME = "SubjectInfoAccess";
public static final String DESCRIPTIONS = "descriptions";
/**
* The List of AccessDescription objects.
*/
private List<AccessDescription> accessDescriptions;
/**
* Create an SubjectInfoAccessExtension from a List of
* AccessDescription; the criticality is set to false.
*
* @param accessDescriptions the List of AccessDescription
* @throws IOException on error
*/
public SubjectInfoAccessExtension(
List<AccessDescription> accessDescriptions) throws IOException {
this.extensionId = PKIXExtensions.SubjectInfoAccess_Id;
this.critical = false;
this.accessDescriptions = accessDescriptions;
encodeThis();
}
/**
* Create the extension from the passed DER encoded value of the same.
*
* @param critical true if the extension is to be treated as critical.
* @param value Array of DER encoded bytes of the actual value.
* @exception IOException on error.
*/
public SubjectInfoAccessExtension(Boolean critical, Object value)
throws IOException {
this.extensionId = PKIXExtensions.SubjectInfoAccess_Id;
this.critical = critical.booleanValue();
if (!(value instanceof byte[])) {
throw new IOException("Illegal argument type");
}
extensionValue = (byte[])value;
DerValue val = new DerValue(extensionValue);
if (val.tag != DerValue.tag_Sequence) {
throw new IOException("Invalid encoding for " +
"SubjectInfoAccessExtension.");
}
accessDescriptions = new ArrayList<AccessDescription>();
while (val.data.available() != 0) {
DerValue seq = val.data.getDerValue();
AccessDescription accessDescription = new AccessDescription(seq);
accessDescriptions.add(accessDescription);
}
}
/**
* Return the list of AccessDescription objects.
*/
public List<AccessDescription> getAccessDescriptions() {
return accessDescriptions;
}
/**
* Return the name of this attribute.
*/
public String getName() {
return NAME;
}
/**
* Write the extension to the DerOutputStream.
*
* @param out the DerOutputStream to write the extension to.
* @exception IOException on encoding errors.
*/
public void encode(OutputStream out) throws IOException {
DerOutputStream tmp = new DerOutputStream();
if (this.extensionValue == null) {
this.extensionId = PKIXExtensions.SubjectInfoAccess_Id;
this.critical = false;
encodeThis();
}
super.encode(tmp);
out.write(tmp.toByteArray());
}
/**
* Set the attribute value.
*/
@SuppressWarnings("unchecked") // Checked with instanceof
public void set(String name, Object obj) throws IOException {
if (name.equalsIgnoreCase(DESCRIPTIONS)) {
if (!(obj instanceof List)) {
throw new IOException("Attribute value should be of type List.");
}
accessDescriptions = (List<AccessDescription>)obj;
} else {
throw new IOException("Attribute name [" + name +
"] not recognized by " +
"CertAttrSet:SubjectInfoAccessExtension.");
}
encodeThis();
}
/**
* Get the attribute value.
*/
public List<AccessDescription> get(String name) throws IOException {
if (name.equalsIgnoreCase(DESCRIPTIONS)) {
return accessDescriptions;
} else {
throw new IOException("Attribute name [" + name +
"] not recognized by " +
"CertAttrSet:SubjectInfoAccessExtension.");
}
}
/**
* Delete the attribute value.
*/
public void delete(String name) throws IOException {
if (name.equalsIgnoreCase(DESCRIPTIONS)) {
accessDescriptions =
Collections.<AccessDescription>emptyList();
} else {
throw new IOException("Attribute name [" + name +
"] not recognized by " +
"CertAttrSet:SubjectInfoAccessExtension.");
}
encodeThis();
}
/**
* Return an enumeration of names of attributes existing within this
* attribute.
*/
public Enumeration<String> getElements() {
AttributeNameEnumeration elements = new AttributeNameEnumeration();
elements.addElement(DESCRIPTIONS);
return elements.elements();
}
// Encode this extension value
private void encodeThis() throws IOException {
if (accessDescriptions.isEmpty()) {
this.extensionValue = null;
} else {
DerOutputStream ads = new DerOutputStream();
for (AccessDescription accessDescription : accessDescriptions) {
accessDescription.encode(ads);
}
DerOutputStream seq = new DerOutputStream();
seq.write(DerValue.tag_Sequence, ads);
this.extensionValue = seq.toByteArray();
}
}
/**
* Return the extension as user readable string.
*/
public String toString() {
return super.toString() + "SubjectInfoAccess [\n "
+ accessDescriptions + "\n]\n";
}
}

View File

@@ -0,0 +1,198 @@
/*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Enumeration;
import sun.security.util.*;
/**
* Represent the Subject Key Identifier Extension.
*
* This extension, if present, provides a means of identifying the particular
* public key used in an application. This extension by default is marked
* non-critical.
*
* <p>Extensions are addiitonal attributes which can be inserted in a X509
* v3 certificate. For example a "Driving License Certificate" could have
* the driving license number as a extension.
*
* <p>Extensions are represented as a sequence of the extension identifier
* (Object Identifier), a boolean flag stating whether the extension is to
* be treated as being critical and the extension value itself (this is again
* a DER encoding of the extension value).
*
* @author Amit Kapoor
* @author Hemma Prafullchandra
* @see Extension
* @see CertAttrSet
*/
public class SubjectKeyIdentifierExtension extends Extension
implements CertAttrSet<String> {
/**
* Identifier for this attribute, to be used with the
* get, set, delete methods of Certificate, x509 type.
*/
public static final String IDENT =
"x509.info.extensions.SubjectKeyIdentifier";
/**
* Attribute names.
*/
public static final String NAME = "SubjectKeyIdentifier";
public static final String KEY_ID = "key_id";
// Private data member
private KeyIdentifier id = null;
// Encode this extension value
private void encodeThis() throws IOException {
if (id == null) {
this.extensionValue = null;
return;
}
DerOutputStream os = new DerOutputStream();
id.encode(os);
this.extensionValue = os.toByteArray();
}
/**
* Create a SubjectKeyIdentifierExtension with the passed octet string.
* The criticality is set to False.
* @param octetString the octet string identifying the key identifier.
*/
public SubjectKeyIdentifierExtension(byte[] octetString)
throws IOException {
id = new KeyIdentifier(octetString);
this.extensionId = PKIXExtensions.SubjectKey_Id;
this.critical = false;
encodeThis();
}
/**
* Create the extension from the passed DER encoded value.
*
* @param critical true if the extension is to be treated as critical.
* @param value an array of DER encoded bytes of the actual value.
* @exception ClassCastException if value is not an array of bytes
* @exception IOException on error.
*/
public SubjectKeyIdentifierExtension(Boolean critical, Object value)
throws IOException {
this.extensionId = PKIXExtensions.SubjectKey_Id;
this.critical = critical.booleanValue();
this.extensionValue = (byte[]) value;
DerValue val = new DerValue(this.extensionValue);
this.id = new KeyIdentifier(val);
}
/**
* Returns a printable representation.
*/
public String toString() {
return super.toString() + "SubjectKeyIdentifier [\n"
+ String.valueOf(id) + "]\n";
}
/**
* Write the extension to the OutputStream.
*
* @param out the OutputStream to write the extension to.
* @exception IOException on encoding errors.
*/
public void encode(OutputStream out) throws IOException {
DerOutputStream tmp = new DerOutputStream();
if (extensionValue == null) {
extensionId = PKIXExtensions.SubjectKey_Id;
critical = false;
encodeThis();
}
super.encode(tmp);
out.write(tmp.toByteArray());
}
/**
* Set the attribute value.
*/
public void set(String name, Object obj) throws IOException {
if (name.equalsIgnoreCase(KEY_ID)) {
if (!(obj instanceof KeyIdentifier)) {
throw new IOException("Attribute value should be of" +
" type KeyIdentifier.");
}
id = (KeyIdentifier)obj;
} else {
throw new IOException("Attribute name not recognized by " +
"CertAttrSet:SubjectKeyIdentifierExtension.");
}
encodeThis();
}
/**
* Get the attribute value.
*/
public KeyIdentifier get(String name) throws IOException {
if (name.equalsIgnoreCase(KEY_ID)) {
return (id);
} else {
throw new IOException("Attribute name not recognized by " +
"CertAttrSet:SubjectKeyIdentifierExtension.");
}
}
/**
* Delete the attribute value.
*/
public void delete(String name) throws IOException {
if (name.equalsIgnoreCase(KEY_ID)) {
id = null;
} else {
throw new IOException("Attribute name not recognized by " +
"CertAttrSet:SubjectKeyIdentifierExtension.");
}
encodeThis();
}
/**
* Return an enumeration of names of attributes existing within this
* attribute.
*/
public Enumeration<String> getElements() {
AttributeNameEnumeration elements = new AttributeNameEnumeration();
elements.addElement(KEY_ID);
return (elements.elements());
}
/**
* Return the name of this attribute.
*/
public String getName() {
return (NAME);
}
}

View File

@@ -0,0 +1,392 @@
/*
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import sun.security.util.*;
/**
* This class implements the URIName as required by the GeneralNames
* ASN.1 object.
* <p>
* [RFC5280] When the subjectAltName extension contains a URI, the name MUST be
* stored in the uniformResourceIdentifier (an IA5String). The name MUST
* be a non-relative URL, and MUST follow the URL syntax and encoding
* rules specified in [RFC 3986]. The name must include both a scheme
* (e.g., "http" or "ftp") and a scheme-specific-part. The scheme-
* specific-part must include a fully qualified domain name or IP
* address as the host.
* <p>
* As specified in [RFC 3986], the scheme name is not case-sensitive
* (e.g., "http" is equivalent to "HTTP"). The host part is also not
* case-sensitive, but other components of the scheme-specific-part may
* be case-sensitive. When comparing URIs, conforming implementations
* MUST compare the scheme and host without regard to case, but assume
* the remainder of the scheme-specific-part is case sensitive.
* <p>
* [RFC1738] In general, URLs are written as follows:
* <pre>
* <scheme>:<scheme-specific-part>
* </pre>
* A URL contains the name of the scheme being used (<scheme>) followed
* by a colon and then a string (the <scheme-specific-part>) whose
* interpretation depends on the scheme.
* <p>
* While the syntax for the rest of the URL may vary depending on the
* particular scheme selected, URL schemes that involve the direct use
* of an IP-based protocol to a specified host on the Internet use a
* common syntax for the scheme-specific data:
* <pre>
* //<user>:<password>@<host>:<port>/<url-path>
* </pre>
* [RFC2732] specifies that an IPv6 address contained inside a URL
* must be enclosed in square brackets (to allow distinguishing the
* colons that separate IPv6 components from the colons that separate
* scheme-specific data.
* <p>
* @author Amit Kapoor
* @author Hemma Prafullchandra
* @author Sean Mullan
* @author Steve Hanna
* @see GeneralName
* @see GeneralNames
* @see GeneralNameInterface
*/
public class URIName implements GeneralNameInterface {
// private attributes
private URI uri;
private String host;
private DNSName hostDNS;
private IPAddressName hostIP;
/**
* Create the URIName object from the passed encoded Der value.
*
* @param derValue the encoded DER URIName.
* @exception IOException on error.
*/
public URIName(DerValue derValue) throws IOException {
this(derValue.getIA5String());
}
/**
* Create the URIName object with the specified name.
*
* @param name the URIName.
* @throws IOException if name is not a proper URIName
*/
public URIName(String name) throws IOException {
try {
uri = new URI(name);
} catch (URISyntaxException use) {
throw new IOException("invalid URI name:" + name, use);
}
if (uri.getScheme() == null) {
throw new IOException("URI name must include scheme:" + name);
}
host = uri.getHost();
// RFC 5280 says that the host should be non-null, but we allow it to
// be null because some widely deployed certificates contain CDP
// extensions with URIs that have no hostname (see bugs 4802236 and
// 5107944).
if (host != null) {
if (host.charAt(0) == '[') {
// Verify host is a valid IPv6 address name
String ipV6Host = host.substring(1, host.length()-1);
try {
hostIP = new IPAddressName(ipV6Host);
} catch (IOException ioe) {
throw new IOException("invalid URI name (host " +
"portion is not a valid IPv6 address):" + name);
}
} else {
try {
hostDNS = new DNSName(host);
} catch (IOException ioe) {
// Not a valid DNSName; see if it is a valid IPv4
// IPAddressName
try {
hostIP = new IPAddressName(host);
} catch (Exception ioe2) {
throw new IOException("invalid URI name (host " +
"portion is not a valid DNSName, IPv4 address," +
" or IPv6 address):" + name);
}
}
}
}
}
/**
* Create the URIName object with the specified name constraint. URI
* name constraints syntax is different than SubjectAltNames, etc. See
* 4.2.1.10 of RFC 5280.
*
* @param value the URI name constraint
* @throws IOException if name is not a proper URI name constraint
*/
public static URIName nameConstraint(DerValue value) throws IOException {
URI uri;
String name = value.getIA5String();
try {
uri = new URI(name);
} catch (URISyntaxException use) {
throw new IOException("invalid URI name constraint:" + name, use);
}
if (uri.getScheme() == null) {
String host = uri.getSchemeSpecificPart();
try {
DNSName hostDNS;
if (host.startsWith(".")) {
hostDNS = new DNSName(host.substring(1));
} else {
hostDNS = new DNSName(host);
}
return new URIName(uri, host, hostDNS);
} catch (IOException ioe) {
throw new IOException("invalid URI name constraint:" + name, ioe);
}
} else {
throw new IOException("invalid URI name constraint (should not " +
"include scheme):" + name);
}
}
URIName(URI uri, String host, DNSName hostDNS) {
this.uri = uri;
this.host = host;
this.hostDNS = hostDNS;
}
/**
* Return the type of the GeneralName.
*/
public int getType() {
return GeneralNameInterface.NAME_URI;
}
/**
* Encode the URI name into the DerOutputStream.
*
* @param out the DER stream to encode the URIName to.
* @exception IOException on encoding errors.
*/
public void encode(DerOutputStream out) throws IOException {
out.putIA5String(uri.toASCIIString());
}
/**
* Convert the name into user readable string.
*/
public String toString() {
return "URIName: " + uri.toString();
}
/**
* Compares this name with another, for equality.
*
* @return true iff the names are equivalent according to RFC2459.
*/
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof URIName)) {
return false;
}
URIName other = (URIName) obj;
return uri.equals(other.getURI());
}
/**
* Returns the URIName as a java.net.URI object
*/
public URI getURI() {
return uri;
}
/**
* Returns this URI name.
*/
public String getName() {
return uri.toString();
}
/**
* Return the scheme name portion of a URIName
*
* @returns scheme portion of full name
*/
public String getScheme() {
return uri.getScheme();
}
/**
* Return the host name or IP address portion of the URIName
*
* @returns host name or IP address portion of full name
*/
public String getHost() {
return host;
}
/**
* Return the host object type; if host name is a
* DNSName, then this host object does not include any
* initial "." on the name.
*
* @returns host name as DNSName or IPAddressName
*/
public Object getHostObject() {
if (hostIP != null) {
return hostIP;
} else {
return hostDNS;
}
}
/**
* Returns the hash code value for this object.
*
* @return a hash code value for this object.
*/
public int hashCode() {
return uri.hashCode();
}
/**
* Return type of constraint inputName places on this name:<ul>
* <li>NAME_DIFF_TYPE = -1: input name is different type from name
* (i.e. does not constrain).
* <li>NAME_MATCH = 0: input name matches name.
* <li>NAME_NARROWS = 1: input name narrows name (is lower in the naming
* subtree)
* <li>NAME_WIDENS = 2: input name widens name (is higher in the naming
* subtree)
* <li>NAME_SAME_TYPE = 3: input name does not match or narrow name, but
* is same type.
* </ul>.
* These results are used in checking NameConstraints during
* certification path verification.
* <p>
* RFC5280: For URIs, the constraint applies to the host part of the name.
* The constraint may specify a host or a domain. Examples would be
* "foo.bar.com"; and ".xyz.com". When the the constraint begins with
* a period, it may be expanded with one or more subdomains. That is,
* the constraint ".xyz.com" is satisfied by both abc.xyz.com and
* abc.def.xyz.com. However, the constraint ".xyz.com" is not satisfied
* by "xyz.com". When the constraint does not begin with a period, it
* specifies a host.
* <p>
* @param inputName to be checked for being constrained
* @returns constraint type above
* @throws UnsupportedOperationException if name is not exact match, but
* narrowing and widening are not supported for this name type.
*/
public int constrains(GeneralNameInterface inputName)
throws UnsupportedOperationException {
int constraintType;
if (inputName == null) {
constraintType = NAME_DIFF_TYPE;
} else if (inputName.getType() != NAME_URI) {
constraintType = NAME_DIFF_TYPE;
} else {
// Assuming from here on that one or both of these is
// actually a URI name constraint (not a URI), so we
// only need to compare the host portion of the name
String otherHost = ((URIName)inputName).getHost();
// Quick check for equality
if (otherHost.equalsIgnoreCase(host)) {
constraintType = NAME_MATCH;
} else {
Object otherHostObject = ((URIName)inputName).getHostObject();
if ((hostDNS == null) ||
!(otherHostObject instanceof DNSName)) {
// If one (or both) is an IP address, only same type
constraintType = NAME_SAME_TYPE;
} else {
// Both host portions are DNSNames. Are they domains?
boolean thisDomain = (host.charAt(0) == '.');
boolean otherDomain = (otherHost.charAt(0) == '.');
DNSName otherDNS = (DNSName) otherHostObject;
// Run DNSName.constrains.
constraintType = hostDNS.constrains(otherDNS);
// If neither one is a domain, then they can't
// widen or narrow. That's just SAME_TYPE.
if ((!thisDomain && !otherDomain) &&
((constraintType == NAME_WIDENS) ||
(constraintType == NAME_NARROWS))) {
constraintType = NAME_SAME_TYPE;
}
// If one is a domain and the other isn't,
// then they can't match. The one that's a
// domain doesn't include the one that's
// not a domain.
if ((thisDomain != otherDomain) &&
(constraintType == NAME_MATCH)) {
if (thisDomain) {
constraintType = NAME_WIDENS;
} else {
constraintType = NAME_NARROWS;
}
}
}
}
}
return constraintType;
}
/**
* Return subtree depth of this name for purposes of determining
* NameConstraints minimum and maximum bounds and for calculating
* path lengths in name subtrees.
*
* @returns distance of name from root
* @throws UnsupportedOperationException if not supported for this name type
*/
public int subtreeDepth() throws UnsupportedOperationException {
DNSName dnsName = null;
try {
dnsName = new DNSName(host);
} catch (IOException ioe) {
throw new UnsupportedOperationException(ioe.getMessage());
}
return dnsName.subtreeDepth();
}
}

View File

@@ -0,0 +1,116 @@
/*
* Copyright (c) 1997, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.math.BigInteger;
import sun.misc.HexDumpEncoder;
import sun.security.util.*;
/**
* This class defines the UniqueIdentity class used by certificates.
*
* @author Amit Kapoor
* @author Hemma Prafullchandra
*/
public class UniqueIdentity {
// Private data members
private BitArray id;
/**
* The default constructor for this class.
*
* @param id the byte array containing the unique identifier.
*/
public UniqueIdentity(BitArray id) {
this.id = id;
}
/**
* The default constructor for this class.
*
* @param id the byte array containing the unique identifier.
*/
public UniqueIdentity(byte[] id) {
this.id = new BitArray(id.length*8, id);
}
/**
* Create the object, decoding the values from the passed DER stream.
*
* @param in the DerInputStream to read the UniqueIdentity from.
* @exception IOException on decoding errors.
*/
public UniqueIdentity(DerInputStream in) throws IOException {
DerValue derVal = in.getDerValue();
id = derVal.getUnalignedBitString(true);
}
/**
* Create the object, decoding the values from the passed DER stream.
*
* @param derVal the DerValue decoded from the stream.
* @param tag the tag the value is encoded under.
* @exception IOException on decoding errors.
*/
public UniqueIdentity(DerValue derVal) throws IOException {
id = derVal.getUnalignedBitString(true);
}
/**
* Return the UniqueIdentity as a printable string.
*/
public String toString() {
return ("UniqueIdentity:" + id.toString() + "\n");
}
/**
* Encode the UniqueIdentity in DER form to the stream.
*
* @param out the DerOutputStream to marshal the contents to.
* @param tag enocode it under the following tag.
* @exception IOException on errors.
*/
public void encode(DerOutputStream out, byte tag) throws IOException {
byte[] bytes = id.toByteArray();
int excessBits = bytes.length*8 - id.length();
out.write(tag);
out.putLength(bytes.length + 1);
out.write(excessBits);
out.write(bytes);
}
/**
* Return the unique id.
*/
public boolean[] getId() {
if (id == null) return null;
return id.toBooleanArray();
}
}

View File

@@ -0,0 +1,423 @@
/*
* Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import sun.security.util.DerValue;
import sun.security.util.DerOutputStream;
/**
* This class defines the X400Address of the GeneralName choice.
* <p>
* The ASN.1 syntax for this is:
* <pre>
* ORAddress ::= SEQUENCE {
* built-in-standard-attributes BuiltInStandardAttributes,
* built-in-domain-defined-attributes
* BuiltInDomainDefinedAttributes OPTIONAL,
* -- see also teletex-domain-defined-attributes
* extension-attributes ExtensionAttributes OPTIONAL }
* -- The OR-address is semantically absent from the OR-name if the
* -- built-in-standard-attribute sequence is empty and the
* -- built-in-domain-defined-attributes and extension-attributes are
* -- both omitted.
*
* -- Built-in Standard Attributes
*
* BuiltInStandardAttributes ::= SEQUENCE {
* country-name CountryName OPTIONAL,
* administration-domain-name AdministrationDomainName OPTIONAL,
* network-address [0] NetworkAddress OPTIONAL,
* -- see also extended-network-address
* terminal-identifier [1] TerminalIdentifier OPTIONAL,
* private-domain-name [2] PrivateDomainName OPTIONAL,
* organization-name [3] OrganizationName OPTIONAL,
* -- see also teletex-organization-name
* numeric-user-identifier [4] NumericUserIdentifier OPTIONAL,
* personal-name [5] PersonalName OPTIONAL,
* -- see also teletex-personal-name
* organizational-unit-names [6] OrganizationalUnitNames OPTIONAL
* -- see also teletex-organizational-unit-names -- }
*
* CountryName ::= [APPLICATION 1] CHOICE {
* x121-dcc-code NumericString
* (SIZE (ub-country-name-numeric-length)),
* iso-3166-alpha2-code PrintableString
* (SIZE (ub-country-name-alpha-length)) }
*
* AdministrationDomainName ::= [APPLICATION 2] CHOICE {
* numeric NumericString (SIZE (0..ub-domain-name-length)),
* printable PrintableString (SIZE (0..ub-domain-name-length)) }
*
* NetworkAddress ::= X121Address -- see also extended-network-address
*
* X121Address ::= NumericString (SIZE (1..ub-x121-address-length))
*
* TerminalIdentifier ::= PrintableString (SIZE (1..ub-terminal-id-length))
*
* PrivateDomainName ::= CHOICE {
* numeric NumericString (SIZE (1..ub-domain-name-length)),
* printable PrintableString (SIZE (1..ub-domain-name-length)) }
*
* OrganizationName ::= PrintableString
* (SIZE (1..ub-organization-name-length))
* -- see also teletex-organization-name
*
* NumericUserIdentifier ::= NumericString
* (SIZE (1..ub-numeric-user-id-length))
*
* PersonalName ::= SET {
* surname [0] PrintableString (SIZE (1..ub-surname-length)),
* given-name [1] PrintableString
* (SIZE (1..ub-given-name-length)) OPTIONAL,
* initials [2] PrintableString (SIZE (1..ub-initials-length)) OPTIONAL,
* generation-qualifier [3] PrintableString
* (SIZE (1..ub-generation-qualifier-length)) OPTIONAL }
* -- see also teletex-personal-name
*
* OrganizationalUnitNames ::= SEQUENCE SIZE (1..ub-organizational-units)
* OF OrganizationalUnitName
* -- see also teletex-organizational-unit-names
*
* OrganizationalUnitName ::= PrintableString (SIZE
* (1..ub-organizational-unit-name-length))
*
* -- Built-in Domain-defined Attributes
*
* BuiltInDomainDefinedAttributes ::= SEQUENCE SIZE
* (1..ub-domain-defined-attributes) OF
* BuiltInDomainDefinedAttribute
*
* BuiltInDomainDefinedAttribute ::= SEQUENCE {
* type PrintableString (SIZE
* (1..ub-domain-defined-attribute-type-length)),
* value PrintableString (SIZE
* (1..ub-domain-defined-attribute-value-length))}
*
* -- Extension Attributes
*
* ExtensionAttributes ::= SET SIZE (1..ub-extension-attributes) OF
* ExtensionAttribute
*
* ExtensionAttribute ::= SEQUENCE {
* extension-attribute-type [0] INTEGER (0..ub-extension-attributes),
* extension-attribute-value [1]
* ANY DEFINED BY extension-attribute-type }
*
* -- Extension types and attribute values
* --
*
* common-name INTEGER ::= 1
*
* CommonName ::= PrintableString (SIZE (1..ub-common-name-length))
*
* teletex-common-name INTEGER ::= 2
*
* TeletexCommonName ::= TeletexString (SIZE (1..ub-common-name-length))
*
* teletex-organization-name INTEGER ::= 3
*
* TeletexOrganizationName ::=
* TeletexString (SIZE (1..ub-organization-name-length))
*
* teletex-personal-name INTEGER ::= 4
*
* TeletexPersonalName ::= SET {
* surname [0] TeletexString (SIZE (1..ub-surname-length)),
* given-name [1] TeletexString
* (SIZE (1..ub-given-name-length)) OPTIONAL,
* initials [2] TeletexString (SIZE (1..ub-initials-length)) OPTIONAL,
* generation-qualifier [3] TeletexString (SIZE
* (1..ub-generation-qualifier-length)) OPTIONAL }
*
* teletex-organizational-unit-names INTEGER ::= 5
*
* TeletexOrganizationalUnitNames ::= SEQUENCE SIZE
* (1..ub-organizational-units) OF TeletexOrganizationalUnitName
*
* TeletexOrganizationalUnitName ::= TeletexString
* (SIZE (1..ub-organizational-unit-name-length))
*
* pds-name INTEGER ::= 7
*
* PDSName ::= PrintableString (SIZE (1..ub-pds-name-length))
*
* physical-delivery-country-name INTEGER ::= 8
*
* PhysicalDeliveryCountryName ::= CHOICE {
* x121-dcc-code NumericString (SIZE (ub-country-name-numeric-length)),
* iso-3166-alpha2-code PrintableString
* (SIZE (ub-country-name-alpha-length)) }
*
* postal-code INTEGER ::= 9
*
* PostalCode ::= CHOICE {
* numeric-code NumericString (SIZE (1..ub-postal-code-length)),
* printable-code PrintableString (SIZE (1..ub-postal-code-length)) }
*
* physical-delivery-office-name INTEGER ::= 10
*
* PhysicalDeliveryOfficeName ::= PDSParameter
*
* physical-delivery-office-number INTEGER ::= 11
*
* PhysicalDeliveryOfficeNumber ::= PDSParameter
*
* extension-OR-address-components INTEGER ::= 12
*
* ExtensionORAddressComponents ::= PDSParameter
*
* physical-delivery-personal-name INTEGER ::= 13
*
* PhysicalDeliveryPersonalName ::= PDSParameter
*
* physical-delivery-organization-name INTEGER ::= 14
*
* PhysicalDeliveryOrganizationName ::= PDSParameter
*
* extension-physical-delivery-address-components INTEGER ::= 15
*
* ExtensionPhysicalDeliveryAddressComponents ::= PDSParameter
*
* unformatted-postal-address INTEGER ::= 16
*
* UnformattedPostalAddress ::= SET {
* printable-address SEQUENCE SIZE (1..ub-pds-physical-address-lines) OF
* PrintableString (SIZE (1..ub-pds-parameter-length)) OPTIONAL,
* teletex-string TeletexString
* (SIZE (1..ub-unformatted-address-length)) OPTIONAL }
*
* street-address INTEGER ::= 17
*
* StreetAddress ::= PDSParameter
*
* post-office-box-address INTEGER ::= 18
*
* PostOfficeBoxAddress ::= PDSParameter
*
* poste-restante-address INTEGER ::= 19
*
* PosteRestanteAddress ::= PDSParameter
*
* unique-postal-name INTEGER ::= 20
*
* UniquePostalName ::= PDSParameter
*
* local-postal-attributes INTEGER ::= 21
*
* LocalPostalAttributes ::= PDSParameter
*
* PDSParameter ::= SET {
* printable-string PrintableString
* (SIZE(1..ub-pds-parameter-length)) OPTIONAL,
* teletex-string TeletexString
* (SIZE(1..ub-pds-parameter-length)) OPTIONAL }
*
* extended-network-address INTEGER ::= 22
*
* ExtendedNetworkAddress ::= CHOICE {
* e163-4-address SEQUENCE {
* number [0] NumericString (SIZE (1..ub-e163-4-number-length)),
* sub-address [1] NumericString
* (SIZE (1..ub-e163-4-sub-address-length)) OPTIONAL },
* psap-address [0] PresentationAddress }
*
* PresentationAddress ::= SEQUENCE {
* pSelector [0] EXPLICIT OCTET STRING OPTIONAL,
* sSelector [1] EXPLICIT OCTET STRING OPTIONAL,
* tSelector [2] EXPLICIT OCTET STRING OPTIONAL,
* nAddresses [3] EXPLICIT SET SIZE (1..MAX) OF OCTET STRING }
*
* terminal-type INTEGER ::= 23
*
* TerminalType ::= INTEGER {
* telex (3),
* teletex (4),
* g3-facsimile (5),
* g4-facsimile (6),
* ia5-terminal (7),
* videotex (8) } (0..ub-integer-options)
*
* -- Extension Domain-defined Attributes
*
* teletex-domain-defined-attributes INTEGER ::= 6
*
* TeletexDomainDefinedAttributes ::= SEQUENCE SIZE
* (1..ub-domain-defined-attributes) OF TeletexDomainDefinedAttribute
*
* TeletexDomainDefinedAttribute ::= SEQUENCE {
* type TeletexString
* (SIZE (1..ub-domain-defined-attribute-type-length)),
* value TeletexString
* (SIZE (1..ub-domain-defined-attribute-value-length)) }
*
* -- specifications of Upper Bounds shall be regarded as mandatory
* -- from Annex B of ITU-T X.411 Reference Definition of MTS Parameter
* -- Upper Bounds
*
* -- Upper Bounds
* ub-name INTEGER ::= 32768
* ub-common-name INTEGER ::= 64
* ub-locality-name INTEGER ::= 128
* ub-state-name INTEGER ::= 128
* ub-organization-name INTEGER ::= 64
* ub-organizational-unit-name INTEGER ::= 64
* ub-title INTEGER ::= 64
* ub-match INTEGER ::= 128
*
* ub-emailaddress-length INTEGER ::= 128
*
* ub-common-name-length INTEGER ::= 64
* ub-country-name-alpha-length INTEGER ::= 2
* ub-country-name-numeric-length INTEGER ::= 3
* ub-domain-defined-attributes INTEGER ::= 4
* ub-domain-defined-attribute-type-length INTEGER ::= 8
* ub-domain-defined-attribute-value-length INTEGER ::= 128
* ub-domain-name-length INTEGER ::= 16
* ub-extension-attributes INTEGER ::= 256
* ub-e163-4-number-length INTEGER ::= 15
* ub-e163-4-sub-address-length INTEGER ::= 40
* ub-generation-qualifier-length INTEGER ::= 3
* ub-given-name-length INTEGER ::= 16
* ub-initials-length INTEGER ::= 5
* ub-integer-options INTEGER ::= 256
* ub-numeric-user-id-length INTEGER ::= 32
* ub-organization-name-length INTEGER ::= 64
* ub-organizational-unit-name-length INTEGER ::= 32
* ub-organizational-units INTEGER ::= 4
* ub-pds-name-length INTEGER ::= 16
* ub-pds-parameter-length INTEGER ::= 30
* ub-pds-physical-address-lines INTEGER ::= 6
* ub-postal-code-length INTEGER ::= 16
* ub-surname-length INTEGER ::= 40
* ub-terminal-id-length INTEGER ::= 24
* ub-unformatted-address-length INTEGER ::= 180
* ub-x121-address-length INTEGER ::= 16
*
* -- Note - upper bounds on string types, such as TeletexString, are
* -- measured in characters. Excepting PrintableString or IA5String, a
* -- significantly greater number of octets will be required to hold
* -- such a value. As a minimum, 16 octets, or twice the specified upper
* -- bound, whichever is the larger, should be allowed for TeletexString.
* -- For UTF8String or UniversalString at least four times the upper
* -- bound should be allowed.
* </pre>
*
* @author Anne Anderson
* @since 1.4
* @see GeneralName
* @see GeneralNames
* @see GeneralNameInterface
*/
public class X400Address implements GeneralNameInterface {
// Private data members
byte[] nameValue = null;
/**
* Create the X400Address object from the specified byte array
*
* @param nameValue value of the name as a byte array
*/
public X400Address(byte[] value) {
nameValue = value;
}
/**
* Create the X400Address object from the passed encoded Der value.
*
* @param derValue the encoded DER X400Address.
* @exception IOException on error.
*/
public X400Address(DerValue derValue) throws IOException {
nameValue = derValue.toByteArray();
}
/**
* Return the type of the GeneralName.
*/
public int getType() {
return (GeneralNameInterface.NAME_X400);
}
/**
* Encode the X400 name into the DerOutputStream.
*
* @param out the DER stream to encode the X400Address to.
* @exception IOException on encoding errors.
*/
public void encode(DerOutputStream out) throws IOException {
DerValue derValue = new DerValue(nameValue);
out.putDerValue(derValue);
}
/**
* Return the printable string.
*/
public String toString() {
return ("X400Address: <DER-encoded value>");
}
/**
* Return type of constraint inputName places on this name:<ul>
* <li>NAME_DIFF_TYPE = -1: input name is different type from name (i.e. does not constrain).
* <li>NAME_MATCH = 0: input name matches name.
* <li>NAME_NARROWS = 1: input name narrows name (is lower in the naming subtree)
* <li>NAME_WIDENS = 2: input name widens name (is higher in the naming subtree)
* <li>NAME_SAME_TYPE = 3: input name does not match or narrow name, but is same type.
* </ul>. These results are used in checking NameConstraints during
* certification path verification.
*
* @param inputName to be checked for being constrained
* @returns constraint type above
* @throws UnsupportedOperationException if name is same type, but comparison operations are
* not supported for this name type.
*/
public int constrains(GeneralNameInterface inputName) throws UnsupportedOperationException {
int constraintType;
if (inputName == null)
constraintType = NAME_DIFF_TYPE;
else if (inputName.getType() != NAME_X400)
constraintType = NAME_DIFF_TYPE;
else
//Narrowing, widening, and match constraints not defined in rfc2459 for X400Address
throw new UnsupportedOperationException("Narrowing, widening, and match are not supported for X400Address.");
return constraintType;
}
/**
* Return subtree depth of this name for purposes of determining
* NameConstraints minimum and maximum bounds and for calculating
* path lengths in name subtrees.
*
* @returns distance of name from root
* @throws UnsupportedOperationException if not supported for this name type
*/
public int subtreeDepth() throws UnsupportedOperationException {
throw new UnsupportedOperationException("subtreeDepth not supported for X400Address");
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,71 @@
/*
* Copyright (c) 1997, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
/**
* This class is used to parse attribute names like "x509.info.extensions".
*
* @author Amit Kapoor
* @author Hemma Prafullchandra
*/
public class X509AttributeName {
// Public members
private static final char SEPARATOR = '.';
// Private data members
private String prefix = null;
private String suffix = null;
/**
* Default constructor for the class. Name is of the form
* "x509.info.extensions".
*
* @param name the attribute name.
*/
public X509AttributeName(String name) {
int i = name.indexOf(SEPARATOR);
if (i < 0) {
prefix = name;
} else {
prefix = name.substring(0, i);
suffix = name.substring(i + 1);
}
}
/**
* Return the prefix of the name.
*/
public String getPrefix() {
return (prefix);
}
/**
* Return the suffix of the name.
*/
public String getSuffix() {
return (suffix);
}
}

View File

@@ -0,0 +1,536 @@
/*
* Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.security.cert.CRLException;
import java.security.cert.CRLReason;
import java.security.cert.X509CRLEntry;
import java.math.BigInteger;
import java.util.*;
import javax.security.auth.x500.X500Principal;
import sun.security.util.*;
import sun.misc.HexDumpEncoder;
/**
* <p>Abstract class for a revoked certificate in a CRL.
* This class is for each entry in the <code>revokedCertificates</code>,
* so it deals with the inner <em>SEQUENCE</em>.
* The ASN.1 definition for this is:
* <pre>
* revokedCertificates SEQUENCE OF SEQUENCE {
* userCertificate CertificateSerialNumber,
* revocationDate ChoiceOfTime,
* crlEntryExtensions Extensions OPTIONAL
* -- if present, must be v2
* } OPTIONAL
*
* CertificateSerialNumber ::= INTEGER
*
* Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
*
* Extension ::= SEQUENCE {
* extnId OBJECT IDENTIFIER,
* critical BOOLEAN DEFAULT FALSE,
* extnValue OCTET STRING
* -- contains a DER encoding of a value
* -- of the type registered for use with
* -- the extnId object identifier value
* }
* </pre>
*
* @author Hemma Prafullchandra
*/
public class X509CRLEntryImpl extends X509CRLEntry
implements Comparable<X509CRLEntryImpl> {
private SerialNumber serialNumber = null;
private Date revocationDate = null;
private CRLExtensions extensions = null;
private byte[] revokedCert = null;
private X500Principal certIssuer;
private final static boolean isExplicit = false;
/**
* Constructs a revoked certificate entry using the given
* serial number and revocation date.
*
* @param num the serial number of the revoked certificate.
* @param date the Date on which revocation took place.
*/
public X509CRLEntryImpl(BigInteger num, Date date) {
this.serialNumber = new SerialNumber(num);
this.revocationDate = date;
}
/**
* Constructs a revoked certificate entry using the given
* serial number, revocation date and the entry
* extensions.
*
* @param num the serial number of the revoked certificate.
* @param date the Date on which revocation took place.
* @param crlEntryExts the extensions for this entry.
*/
public X509CRLEntryImpl(BigInteger num, Date date,
CRLExtensions crlEntryExts) {
this.serialNumber = new SerialNumber(num);
this.revocationDate = date;
this.extensions = crlEntryExts;
}
/**
* Unmarshals a revoked certificate from its encoded form.
*
* @param revokedCert the encoded bytes.
* @exception CRLException on parsing errors.
*/
public X509CRLEntryImpl(byte[] revokedCert) throws CRLException {
try {
parse(new DerValue(revokedCert));
} catch (IOException e) {
this.revokedCert = null;
throw new CRLException("Parsing error: " + e.toString());
}
}
/**
* Unmarshals a revoked certificate from its encoded form.
*
* @param derVal the DER value containing the revoked certificate.
* @exception CRLException on parsing errors.
*/
public X509CRLEntryImpl(DerValue derValue) throws CRLException {
try {
parse(derValue);
} catch (IOException e) {
revokedCert = null;
throw new CRLException("Parsing error: " + e.toString());
}
}
/**
* Returns true if this revoked certificate entry has
* extensions, otherwise false.
*
* @return true if this CRL entry has extensions, otherwise
* false.
*/
public boolean hasExtensions() {
return (extensions != null);
}
/**
* Encodes the revoked certificate to an output stream.
*
* @param outStrm an output stream to which the encoded revoked
* certificate is written.
* @exception CRLException on encoding errors.
*/
public void encode(DerOutputStream outStrm) throws CRLException {
try {
if (revokedCert == null) {
DerOutputStream tmp = new DerOutputStream();
// sequence { serialNumber, revocationDate, extensions }
serialNumber.encode(tmp);
if (revocationDate.getTime() < CertificateValidity.YR_2050) {
tmp.putUTCTime(revocationDate);
} else {
tmp.putGeneralizedTime(revocationDate);
}
if (extensions != null)
extensions.encode(tmp, isExplicit);
DerOutputStream seq = new DerOutputStream();
seq.write(DerValue.tag_Sequence, tmp);
revokedCert = seq.toByteArray();
}
outStrm.write(revokedCert);
} catch (IOException e) {
throw new CRLException("Encoding error: " + e.toString());
}
}
/**
* Returns the ASN.1 DER-encoded form of this CRL Entry,
* which corresponds to the inner SEQUENCE.
*
* @exception CRLException if an encoding error occurs.
*/
public byte[] getEncoded() throws CRLException {
return getEncoded0().clone();
}
// Called internally to avoid clone
private byte[] getEncoded0() throws CRLException {
if (revokedCert == null)
this.encode(new DerOutputStream());
return revokedCert;
}
@Override
public X500Principal getCertificateIssuer() {
return certIssuer;
}
void setCertificateIssuer(X500Principal crlIssuer, X500Principal certIssuer) {
if (crlIssuer.equals(certIssuer)) {
this.certIssuer = null;
} else {
this.certIssuer = certIssuer;
}
}
/**
* Gets the serial number from this X509CRLEntry,
* i.e. the <em>userCertificate</em>.
*
* @return the serial number.
*/
public BigInteger getSerialNumber() {
return serialNumber.getNumber();
}
/**
* Gets the revocation date from this X509CRLEntry,
* the <em>revocationDate</em>.
*
* @return the revocation date.
*/
public Date getRevocationDate() {
return new Date(revocationDate.getTime());
}
/**
* This method is the overridden implementation of the getRevocationReason
* method in X509CRLEntry. It is better performance-wise since it returns
* cached values.
*/
@Override
public CRLReason getRevocationReason() {
Extension ext = getExtension(PKIXExtensions.ReasonCode_Id);
if (ext == null) {
return null;
}
CRLReasonCodeExtension rcExt = (CRLReasonCodeExtension) ext;
return rcExt.getReasonCode();
}
/**
* This static method is the default implementation of the
* getRevocationReason method in X509CRLEntry.
*/
public static CRLReason getRevocationReason(X509CRLEntry crlEntry) {
try {
byte[] ext = crlEntry.getExtensionValue("2.5.29.21");
if (ext == null) {
return null;
}
DerValue val = new DerValue(ext);
byte[] data = val.getOctetString();
CRLReasonCodeExtension rcExt =
new CRLReasonCodeExtension(Boolean.FALSE, data);
return rcExt.getReasonCode();
} catch (IOException ioe) {
return null;
}
}
/**
* get Reason Code from CRL entry.
*
* @returns Integer or null, if no such extension
* @throws IOException on error
*/
public Integer getReasonCode() throws IOException {
Object obj = getExtension(PKIXExtensions.ReasonCode_Id);
if (obj == null)
return null;
CRLReasonCodeExtension reasonCode = (CRLReasonCodeExtension)obj;
return reasonCode.get(CRLReasonCodeExtension.REASON);
}
/**
* Returns a printable string of this revoked certificate.
*
* @return value of this revoked certificate in a printable form.
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(serialNumber.toString());
sb.append(" On: " + revocationDate.toString());
if (certIssuer != null) {
sb.append("\n Certificate issuer: " + certIssuer);
}
if (extensions != null) {
Collection<Extension> allEntryExts = extensions.getAllExtensions();
Extension[] exts = allEntryExts.toArray(new Extension[0]);
sb.append("\n CRL Entry Extensions: " + exts.length);
for (int i = 0; i < exts.length; i++) {
sb.append("\n [" + (i+1) + "]: ");
Extension ext = exts[i];
try {
if (OIDMap.getClass(ext.getExtensionId()) == null) {
sb.append(ext.toString());
byte[] extValue = ext.getExtensionValue();
if (extValue != null) {
DerOutputStream out = new DerOutputStream();
out.putOctetString(extValue);
extValue = out.toByteArray();
HexDumpEncoder enc = new HexDumpEncoder();
sb.append("Extension unknown: "
+ "DER encoded OCTET string =\n"
+ enc.encodeBuffer(extValue) + "\n");
}
} else
sb.append(ext.toString()); //sub-class exists
} catch (Exception e) {
sb.append(", Error parsing this extension");
}
}
}
sb.append("\n");
return sb.toString();
}
/**
* Return true if a critical extension is found that is
* not supported, otherwise return false.
*/
public boolean hasUnsupportedCriticalExtension() {
if (extensions == null)
return false;
return extensions.hasUnsupportedCriticalExtension();
}
/**
* Gets a Set of the extension(s) marked CRITICAL in this
* X509CRLEntry. In the returned set, each extension is
* represented by its OID string.
*
* @return a set of the extension oid strings in the
* Object that are marked critical.
*/
public Set<String> getCriticalExtensionOIDs() {
if (extensions == null) {
return null;
}
Set<String> extSet = new TreeSet<>();
for (Extension ex : extensions.getAllExtensions()) {
if (ex.isCritical()) {
extSet.add(ex.getExtensionId().toString());
}
}
return extSet;
}
/**
* Gets a Set of the extension(s) marked NON-CRITICAL in this
* X509CRLEntry. In the returned set, each extension is
* represented by its OID string.
*
* @return a set of the extension oid strings in the
* Object that are marked critical.
*/
public Set<String> getNonCriticalExtensionOIDs() {
if (extensions == null) {
return null;
}
Set<String> extSet = new TreeSet<>();
for (Extension ex : extensions.getAllExtensions()) {
if (!ex.isCritical()) {
extSet.add(ex.getExtensionId().toString());
}
}
return extSet;
}
/**
* Gets the DER encoded OCTET string for the extension value
* (<em>extnValue</em>) identified by the passed in oid String.
* The <code>oid</code> string is
* represented by a set of positive whole number separated
* by ".", that means,<br>
* &lt;positive whole number&gt;.&lt;positive whole number&gt;.&lt;positive
* whole number&gt;.&lt;...&gt;
*
* @param oid the Object Identifier value for the extension.
* @return the DER encoded octet string of the extension value.
*/
public byte[] getExtensionValue(String oid) {
if (extensions == null)
return null;
try {
String extAlias = OIDMap.getName(new ObjectIdentifier(oid));
Extension crlExt = null;
if (extAlias == null) { // may be unknown
ObjectIdentifier findOID = new ObjectIdentifier(oid);
Extension ex = null;
ObjectIdentifier inCertOID;
for (Enumeration<Extension> e = extensions.getElements();
e.hasMoreElements();) {
ex = e.nextElement();
inCertOID = ex.getExtensionId();
if (inCertOID.equals((Object)findOID)) {
crlExt = ex;
break;
}
}
} else
crlExt = extensions.get(extAlias);
if (crlExt == null)
return null;
byte[] extData = crlExt.getExtensionValue();
if (extData == null)
return null;
DerOutputStream out = new DerOutputStream();
out.putOctetString(extData);
return out.toByteArray();
} catch (Exception e) {
return null;
}
}
/**
* get an extension
*
* @param oid ObjectIdentifier of extension desired
* @returns Extension of type <extension> or null, if not found
*/
public Extension getExtension(ObjectIdentifier oid) {
if (extensions == null)
return null;
// following returns null if no such OID in map
//XXX consider cloning this
return extensions.get(OIDMap.getName(oid));
}
private void parse(DerValue derVal)
throws CRLException, IOException {
if (derVal.tag != DerValue.tag_Sequence) {
throw new CRLException("Invalid encoded RevokedCertificate, " +
"starting sequence tag missing.");
}
if (derVal.data.available() == 0)
throw new CRLException("No data encoded for RevokedCertificates");
revokedCert = derVal.toByteArray();
// serial number
DerInputStream in = derVal.toDerInputStream();
DerValue val = in.getDerValue();
this.serialNumber = new SerialNumber(val);
// revocationDate
int nextByte = derVal.data.peekByte();
if ((byte)nextByte == DerValue.tag_UtcTime) {
this.revocationDate = derVal.data.getUTCTime();
} else if ((byte)nextByte == DerValue.tag_GeneralizedTime) {
this.revocationDate = derVal.data.getGeneralizedTime();
} else
throw new CRLException("Invalid encoding for revocation date");
if (derVal.data.available() == 0)
return; // no extensions
// crlEntryExtensions
this.extensions = new CRLExtensions(derVal.toDerInputStream());
}
/**
* Utility method to convert an arbitrary instance of X509CRLEntry
* to a X509CRLEntryImpl. Does a cast if possible, otherwise reparses
* the encoding.
*/
public static X509CRLEntryImpl toImpl(X509CRLEntry entry)
throws CRLException {
if (entry instanceof X509CRLEntryImpl) {
return (X509CRLEntryImpl)entry;
} else {
return new X509CRLEntryImpl(entry.getEncoded());
}
}
/**
* Returns the CertificateIssuerExtension
*
* @return the CertificateIssuerExtension, or null if it does not exist
*/
CertificateIssuerExtension getCertificateIssuerExtension() {
return (CertificateIssuerExtension)
getExtension(PKIXExtensions.CertificateIssuer_Id);
}
/**
* Returns all extensions for this entry in a map
* @return the extension map, can be empty, but not null
*/
public Map<String, java.security.cert.Extension> getExtensions() {
if (extensions == null) {
return Collections.emptyMap();
}
Collection<Extension> exts = extensions.getAllExtensions();
Map<String, java.security.cert.Extension> map = new TreeMap<>();
for (Extension ext : exts) {
map.put(ext.getId(), ext);
}
return map;
}
@Override
public int compareTo(X509CRLEntryImpl that) {
int compSerial = getSerialNumber().compareTo(that.getSerialNumber());
if (compSerial != 0) {
return compSerial;
}
try {
byte[] thisEncoded = this.getEncoded0();
byte[] thatEncoded = that.getEncoded0();
for (int i=0; i<thisEncoded.length && i<thatEncoded.length; i++) {
int a = thisEncoded[i] & 0xff;
int b = thatEncoded[i] & 0xff;
if (a != b) return a-b;
}
return thisEncoded.length -thatEncoded.length;
} catch (CRLException ce) {
return -1;
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,958 @@
/*
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.IOException;
import java.io.OutputStream;
import java.security.cert.*;
import java.util.*;
import sun.security.util.*;
import sun.misc.HexDumpEncoder;
/**
* The X509CertInfo class represents X.509 certificate information.
*
* <P>X.509 certificates have several base data elements, including:<UL>
*
* <LI>The <em>Subject Name</em>, an X.500 Distinguished Name for
* the entity (subject) for which the certificate was issued.
*
* <LI>The <em>Subject Public Key</em>, the public key of the subject.
* This is one of the most important parts of the certificate.
*
* <LI>The <em>Validity Period</em>, a time period (e.g. six months)
* within which the certificate is valid (unless revoked).
*
* <LI>The <em>Issuer Name</em>, an X.500 Distinguished Name for the
* Certificate Authority (CA) which issued the certificate.
*
* <LI>A <em>Serial Number</em> assigned by the CA, for use in
* certificate revocation and other applications.
*
* @author Amit Kapoor
* @author Hemma Prafullchandra
* @see CertAttrSet
* @see X509CertImpl
*/
public class X509CertInfo implements CertAttrSet<String> {
/**
* Identifier for this attribute, to be used with the
* get, set, delete methods of Certificate, x509 type.
*/
public static final String IDENT = "x509.info";
// Certificate attribute names
public static final String NAME = "info";
public static final String DN_NAME = "dname";
public static final String VERSION = CertificateVersion.NAME;
public static final String SERIAL_NUMBER = CertificateSerialNumber.NAME;
public static final String ALGORITHM_ID = CertificateAlgorithmId.NAME;
public static final String ISSUER = "issuer";
public static final String SUBJECT = "subject";
public static final String VALIDITY = CertificateValidity.NAME;
public static final String KEY = CertificateX509Key.NAME;
public static final String ISSUER_ID = "issuerID";
public static final String SUBJECT_ID = "subjectID";
public static final String EXTENSIONS = CertificateExtensions.NAME;
// X509.v1 data
protected CertificateVersion version = new CertificateVersion();
protected CertificateSerialNumber serialNum = null;
protected CertificateAlgorithmId algId = null;
protected X500Name issuer = null;
protected X500Name subject = null;
protected CertificateValidity interval = null;
protected CertificateX509Key pubKey = null;
// X509.v2 & v3 extensions
protected UniqueIdentity issuerUniqueId = null;
protected UniqueIdentity subjectUniqueId = null;
// X509.v3 extensions
protected CertificateExtensions extensions = null;
// Attribute numbers for internal manipulation
private static final int ATTR_VERSION = 1;
private static final int ATTR_SERIAL = 2;
private static final int ATTR_ALGORITHM = 3;
private static final int ATTR_ISSUER = 4;
private static final int ATTR_VALIDITY = 5;
private static final int ATTR_SUBJECT = 6;
private static final int ATTR_KEY = 7;
private static final int ATTR_ISSUER_ID = 8;
private static final int ATTR_SUBJECT_ID = 9;
private static final int ATTR_EXTENSIONS = 10;
// DER encoded CertificateInfo data
private byte[] rawCertInfo = null;
// The certificate attribute name to integer mapping stored here
private static final Map<String,Integer> map = new HashMap<String,Integer>();
static {
map.put(VERSION, Integer.valueOf(ATTR_VERSION));
map.put(SERIAL_NUMBER, Integer.valueOf(ATTR_SERIAL));
map.put(ALGORITHM_ID, Integer.valueOf(ATTR_ALGORITHM));
map.put(ISSUER, Integer.valueOf(ATTR_ISSUER));
map.put(VALIDITY, Integer.valueOf(ATTR_VALIDITY));
map.put(SUBJECT, Integer.valueOf(ATTR_SUBJECT));
map.put(KEY, Integer.valueOf(ATTR_KEY));
map.put(ISSUER_ID, Integer.valueOf(ATTR_ISSUER_ID));
map.put(SUBJECT_ID, Integer.valueOf(ATTR_SUBJECT_ID));
map.put(EXTENSIONS, Integer.valueOf(ATTR_EXTENSIONS));
}
/**
* Construct an uninitialized X509CertInfo on which <a href="#decode">
* decode</a> must later be called (or which may be deserialized).
*/
public X509CertInfo() { }
/**
* Unmarshals a certificate from its encoded form, parsing the
* encoded bytes. This form of constructor is used by agents which
* need to examine and use certificate contents. That is, this is
* one of the more commonly used constructors. Note that the buffer
* must include only a certificate, and no "garbage" may be left at
* the end. If you need to ignore data at the end of a certificate,
* use another constructor.
*
* @param cert the encoded bytes, with no trailing data.
* @exception CertificateParsingException on parsing errors.
*/
public X509CertInfo(byte[] cert) throws CertificateParsingException {
try {
DerValue in = new DerValue(cert);
parse(in);
} catch (IOException e) {
throw new CertificateParsingException(e);
}
}
/**
* Unmarshal a certificate from its encoded form, parsing a DER value.
* This form of constructor is used by agents which need to examine
* and use certificate contents.
*
* @param derVal the der value containing the encoded cert.
* @exception CertificateParsingException on parsing errors.
*/
public X509CertInfo(DerValue derVal) throws CertificateParsingException {
try {
parse(derVal);
} catch (IOException e) {
throw new CertificateParsingException(e);
}
}
/**
* Appends the certificate to an output stream.
*
* @param out an output stream to which the certificate is appended.
* @exception CertificateException on encoding errors.
* @exception IOException on other errors.
*/
public void encode(OutputStream out)
throws CertificateException, IOException {
if (rawCertInfo == null) {
DerOutputStream tmp = new DerOutputStream();
emit(tmp);
rawCertInfo = tmp.toByteArray();
}
out.write(rawCertInfo.clone());
}
/**
* Return an enumeration of names of attributes existing within this
* attribute.
*/
public Enumeration<String> getElements() {
AttributeNameEnumeration elements = new AttributeNameEnumeration();
elements.addElement(VERSION);
elements.addElement(SERIAL_NUMBER);
elements.addElement(ALGORITHM_ID);
elements.addElement(ISSUER);
elements.addElement(VALIDITY);
elements.addElement(SUBJECT);
elements.addElement(KEY);
elements.addElement(ISSUER_ID);
elements.addElement(SUBJECT_ID);
elements.addElement(EXTENSIONS);
return elements.elements();
}
/**
* Return the name of this attribute.
*/
public String getName() {
return(NAME);
}
/**
* Returns the encoded certificate info.
*
* @exception CertificateEncodingException on encoding information errors.
*/
public byte[] getEncodedInfo() throws CertificateEncodingException {
try {
if (rawCertInfo == null) {
DerOutputStream tmp = new DerOutputStream();
emit(tmp);
rawCertInfo = tmp.toByteArray();
}
return rawCertInfo.clone();
} catch (IOException e) {
throw new CertificateEncodingException(e.toString());
} catch (CertificateException e) {
throw new CertificateEncodingException(e.toString());
}
}
/**
* Compares two X509CertInfo objects. This is false if the
* certificates are not both X.509 certs, otherwise it
* compares them as binary data.
*
* @param other the object being compared with this one
* @return true iff the certificates are equivalent
*/
public boolean equals(Object other) {
if (other instanceof X509CertInfo) {
return equals((X509CertInfo) other);
} else {
return false;
}
}
/**
* Compares two certificates, returning false if any data
* differs between the two.
*
* @param other the object being compared with this one
* @return true iff the certificates are equivalent
*/
public boolean equals(X509CertInfo other) {
if (this == other) {
return(true);
} else if (rawCertInfo == null || other.rawCertInfo == null) {
return(false);
} else if (rawCertInfo.length != other.rawCertInfo.length) {
return(false);
}
for (int i = 0; i < rawCertInfo.length; i++) {
if (rawCertInfo[i] != other.rawCertInfo[i]) {
return(false);
}
}
return(true);
}
/**
* Calculates a hash code value for the object. Objects
* which are equal will also have the same hashcode.
*/
public int hashCode() {
int retval = 0;
for (int i = 1; i < rawCertInfo.length; i++) {
retval += rawCertInfo[i] * i;
}
return(retval);
}
/**
* Returns a printable representation of the certificate.
*/
public String toString() {
if (subject == null || pubKey == null || interval == null
|| issuer == null || algId == null || serialNum == null) {
throw new NullPointerException("X.509 cert is incomplete");
}
StringBuilder sb = new StringBuilder();
sb.append("[\n");
sb.append(" " + version.toString() + "\n");
sb.append(" Subject: " + subject.toString() + "\n");
sb.append(" Signature Algorithm: " + algId.toString() + "\n");
sb.append(" Key: " + pubKey.toString() + "\n");
sb.append(" " + interval.toString() + "\n");
sb.append(" Issuer: " + issuer.toString() + "\n");
sb.append(" " + serialNum.toString() + "\n");
// optional v2, v3 extras
if (issuerUniqueId != null) {
sb.append(" Issuer Id:\n" + issuerUniqueId.toString() + "\n");
}
if (subjectUniqueId != null) {
sb.append(" Subject Id:\n" + subjectUniqueId.toString() + "\n");
}
if (extensions != null) {
Collection<Extension> allExts = extensions.getAllExtensions();
Extension[] exts = allExts.toArray(new Extension[0]);
sb.append("\nCertificate Extensions: " + exts.length);
for (int i = 0; i < exts.length; i++) {
sb.append("\n[" + (i+1) + "]: ");
Extension ext = exts[i];
try {
if (OIDMap.getClass(ext.getExtensionId()) == null) {
sb.append(ext.toString());
byte[] extValue = ext.getExtensionValue();
if (extValue != null) {
DerOutputStream out = new DerOutputStream();
out.putOctetString(extValue);
extValue = out.toByteArray();
HexDumpEncoder enc = new HexDumpEncoder();
sb.append("Extension unknown: "
+ "DER encoded OCTET string =\n"
+ enc.encodeBuffer(extValue) + "\n");
}
} else
sb.append(ext.toString()); //sub-class exists
} catch (Exception e) {
sb.append(", Error parsing this extension");
}
}
Map<String,Extension> invalid = extensions.getUnparseableExtensions();
if (invalid.isEmpty() == false) {
sb.append("\nUnparseable certificate extensions: " + invalid.size());
int i = 1;
for (Extension ext : invalid.values()) {
sb.append("\n[" + (i++) + "]: ");
sb.append(ext);
}
}
}
sb.append("\n]");
return sb.toString();
}
/**
* Set the certificate attribute.
*
* @params name the name of the Certificate attribute.
* @params val the value of the Certificate attribute.
* @exception CertificateException on invalid attributes.
* @exception IOException on other errors.
*/
public void set(String name, Object val)
throws CertificateException, IOException {
X509AttributeName attrName = new X509AttributeName(name);
int attr = attributeMap(attrName.getPrefix());
if (attr == 0) {
throw new CertificateException("Attribute name not recognized: "
+ name);
}
// set rawCertInfo to null, so that we are forced to re-encode
rawCertInfo = null;
String suffix = attrName.getSuffix();
switch (attr) {
case ATTR_VERSION:
if (suffix == null) {
setVersion(val);
} else {
version.set(suffix, val);
}
break;
case ATTR_SERIAL:
if (suffix == null) {
setSerialNumber(val);
} else {
serialNum.set(suffix, val);
}
break;
case ATTR_ALGORITHM:
if (suffix == null) {
setAlgorithmId(val);
} else {
algId.set(suffix, val);
}
break;
case ATTR_ISSUER:
setIssuer(val);
break;
case ATTR_VALIDITY:
if (suffix == null) {
setValidity(val);
} else {
interval.set(suffix, val);
}
break;
case ATTR_SUBJECT:
setSubject(val);
break;
case ATTR_KEY:
if (suffix == null) {
setKey(val);
} else {
pubKey.set(suffix, val);
}
break;
case ATTR_ISSUER_ID:
setIssuerUniqueId(val);
break;
case ATTR_SUBJECT_ID:
setSubjectUniqueId(val);
break;
case ATTR_EXTENSIONS:
if (suffix == null) {
setExtensions(val);
} else {
if (extensions == null)
extensions = new CertificateExtensions();
extensions.set(suffix, val);
}
break;
}
}
/**
* Delete the certificate attribute.
*
* @params name the name of the Certificate attribute.
* @exception CertificateException on invalid attributes.
* @exception IOException on other errors.
*/
public void delete(String name)
throws CertificateException, IOException {
X509AttributeName attrName = new X509AttributeName(name);
int attr = attributeMap(attrName.getPrefix());
if (attr == 0) {
throw new CertificateException("Attribute name not recognized: "
+ name);
}
// set rawCertInfo to null, so that we are forced to re-encode
rawCertInfo = null;
String suffix = attrName.getSuffix();
switch (attr) {
case ATTR_VERSION:
if (suffix == null) {
version = null;
} else {
version.delete(suffix);
}
break;
case (ATTR_SERIAL):
if (suffix == null) {
serialNum = null;
} else {
serialNum.delete(suffix);
}
break;
case (ATTR_ALGORITHM):
if (suffix == null) {
algId = null;
} else {
algId.delete(suffix);
}
break;
case (ATTR_ISSUER):
issuer = null;
break;
case (ATTR_VALIDITY):
if (suffix == null) {
interval = null;
} else {
interval.delete(suffix);
}
break;
case (ATTR_SUBJECT):
subject = null;
break;
case (ATTR_KEY):
if (suffix == null) {
pubKey = null;
} else {
pubKey.delete(suffix);
}
break;
case (ATTR_ISSUER_ID):
issuerUniqueId = null;
break;
case (ATTR_SUBJECT_ID):
subjectUniqueId = null;
break;
case (ATTR_EXTENSIONS):
if (suffix == null) {
extensions = null;
} else {
if (extensions != null)
extensions.delete(suffix);
}
break;
}
}
/**
* Get the certificate attribute.
*
* @params name the name of the Certificate attribute.
*
* @exception CertificateException on invalid attributes.
* @exception IOException on other errors.
*/
public Object get(String name)
throws CertificateException, IOException {
X509AttributeName attrName = new X509AttributeName(name);
int attr = attributeMap(attrName.getPrefix());
if (attr == 0) {
throw new CertificateParsingException(
"Attribute name not recognized: " + name);
}
String suffix = attrName.getSuffix();
switch (attr) { // frequently used attributes first
case (ATTR_EXTENSIONS):
if (suffix == null) {
return(extensions);
} else {
if (extensions == null) {
return null;
} else {
return(extensions.get(suffix));
}
}
case (ATTR_SUBJECT):
if (suffix == null) {
return(subject);
} else {
return(getX500Name(suffix, false));
}
case (ATTR_ISSUER):
if (suffix == null) {
return(issuer);
} else {
return(getX500Name(suffix, true));
}
case (ATTR_KEY):
if (suffix == null) {
return(pubKey);
} else {
return(pubKey.get(suffix));
}
case (ATTR_ALGORITHM):
if (suffix == null) {
return(algId);
} else {
return(algId.get(suffix));
}
case (ATTR_VALIDITY):
if (suffix == null) {
return(interval);
} else {
return(interval.get(suffix));
}
case (ATTR_VERSION):
if (suffix == null) {
return(version);
} else {
return(version.get(suffix));
}
case (ATTR_SERIAL):
if (suffix == null) {
return(serialNum);
} else {
return(serialNum.get(suffix));
}
case (ATTR_ISSUER_ID):
return(issuerUniqueId);
case (ATTR_SUBJECT_ID):
return(subjectUniqueId);
}
return null;
}
/*
* Get the Issuer or Subject name
*/
private Object getX500Name(String name, boolean getIssuer)
throws IOException {
if (name.equalsIgnoreCase(X509CertInfo.DN_NAME)) {
return getIssuer ? issuer : subject;
} else if (name.equalsIgnoreCase("x500principal")) {
return getIssuer ? issuer.asX500Principal()
: subject.asX500Principal();
} else {
throw new IOException("Attribute name not recognized.");
}
}
/*
* This routine unmarshals the certificate information.
*/
private void parse(DerValue val)
throws CertificateParsingException, IOException {
DerInputStream in;
DerValue tmp;
if (val.tag != DerValue.tag_Sequence) {
throw new CertificateParsingException("signed fields invalid");
}
rawCertInfo = val.toByteArray();
in = val.data;
// Version
tmp = in.getDerValue();
if (tmp.isContextSpecific((byte)0)) {
version = new CertificateVersion(tmp);
tmp = in.getDerValue();
}
// Serial number ... an integer
serialNum = new CertificateSerialNumber(tmp);
// Algorithm Identifier
algId = new CertificateAlgorithmId(in);
// Issuer name
issuer = new X500Name(in);
if (issuer.isEmpty()) {
throw new CertificateParsingException(
"Empty issuer DN not allowed in X509Certificates");
}
// validity: SEQUENCE { start date, end date }
interval = new CertificateValidity(in);
// subject name
subject = new X500Name(in);
if ((version.compare(CertificateVersion.V1) == 0) &&
subject.isEmpty()) {
throw new CertificateParsingException(
"Empty subject DN not allowed in v1 certificate");
}
// public key
pubKey = new CertificateX509Key(in);
// If more data available, make sure version is not v1.
if (in.available() != 0) {
if (version.compare(CertificateVersion.V1) == 0) {
throw new CertificateParsingException(
"no more data allowed for version 1 certificate");
}
} else {
return;
}
// Get the issuerUniqueId if present
tmp = in.getDerValue();
if (tmp.isContextSpecific((byte)1)) {
issuerUniqueId = new UniqueIdentity(tmp);
if (in.available() == 0)
return;
tmp = in.getDerValue();
}
// Get the subjectUniqueId if present.
if (tmp.isContextSpecific((byte)2)) {
subjectUniqueId = new UniqueIdentity(tmp);
if (in.available() == 0)
return;
tmp = in.getDerValue();
}
// Get the extensions.
if (version.compare(CertificateVersion.V3) != 0) {
throw new CertificateParsingException(
"Extensions not allowed in v2 certificate");
}
if (tmp.isConstructed() && tmp.isContextSpecific((byte)3)) {
extensions = new CertificateExtensions(tmp.data);
}
// verify X.509 V3 Certificate
verifyCert(subject, extensions);
}
/*
* Verify if X.509 V3 Certificate is compliant with RFC 5280.
*/
private void verifyCert(X500Name subject,
CertificateExtensions extensions)
throws CertificateParsingException, IOException {
// if SubjectName is empty, check for SubjectAlternativeNameExtension
if (subject.isEmpty()) {
if (extensions == null) {
throw new CertificateParsingException("X.509 Certificate is " +
"incomplete: subject field is empty, and certificate " +
"has no extensions");
}
SubjectAlternativeNameExtension subjectAltNameExt = null;
SubjectAlternativeNameExtension extValue = null;
GeneralNames names = null;
try {
subjectAltNameExt = (SubjectAlternativeNameExtension)
extensions.get(SubjectAlternativeNameExtension.NAME);
names = subjectAltNameExt.get(
SubjectAlternativeNameExtension.SUBJECT_NAME);
} catch (IOException e) {
throw new CertificateParsingException("X.509 Certificate is " +
"incomplete: subject field is empty, and " +
"SubjectAlternativeName extension is absent");
}
// SubjectAlternativeName extension is empty or not marked critical
if (names == null || names.isEmpty()) {
throw new CertificateParsingException("X.509 Certificate is " +
"incomplete: subject field is empty, and " +
"SubjectAlternativeName extension is empty");
} else if (subjectAltNameExt.isCritical() == false) {
throw new CertificateParsingException("X.509 Certificate is " +
"incomplete: SubjectAlternativeName extension MUST " +
"be marked critical when subject field is empty");
}
}
}
/*
* Marshal the contents of a "raw" certificate into a DER sequence.
*/
private void emit(DerOutputStream out)
throws CertificateException, IOException {
DerOutputStream tmp = new DerOutputStream();
// version number, iff not V1
version.encode(tmp);
// Encode serial number, issuer signing algorithm, issuer name
// and validity
serialNum.encode(tmp);
algId.encode(tmp);
if ((version.compare(CertificateVersion.V1) == 0) &&
(issuer.toString() == null))
throw new CertificateParsingException(
"Null issuer DN not allowed in v1 certificate");
issuer.encode(tmp);
interval.encode(tmp);
// Encode subject (principal) and associated key
if ((version.compare(CertificateVersion.V1) == 0) &&
(subject.toString() == null))
throw new CertificateParsingException(
"Null subject DN not allowed in v1 certificate");
subject.encode(tmp);
pubKey.encode(tmp);
// Encode issuerUniqueId & subjectUniqueId.
if (issuerUniqueId != null) {
issuerUniqueId.encode(tmp, DerValue.createTag(DerValue.TAG_CONTEXT,
false,(byte)1));
}
if (subjectUniqueId != null) {
subjectUniqueId.encode(tmp, DerValue.createTag(DerValue.TAG_CONTEXT,
false,(byte)2));
}
// Write all the extensions.
if (extensions != null) {
extensions.encode(tmp);
}
// Wrap the data; encoding of the "raw" cert is now complete.
out.write(DerValue.tag_Sequence, tmp);
}
/**
* Returns the integer attribute number for the passed attribute name.
*/
private int attributeMap(String name) {
Integer num = map.get(name);
if (num == null) {
return 0;
}
return num.intValue();
}
/**
* Set the version number of the certificate.
*
* @params val the Object class value for the Extensions
* @exception CertificateException on invalid data.
*/
private void setVersion(Object val) throws CertificateException {
if (!(val instanceof CertificateVersion)) {
throw new CertificateException("Version class type invalid.");
}
version = (CertificateVersion)val;
}
/**
* Set the serial number of the certificate.
*
* @params val the Object class value for the CertificateSerialNumber
* @exception CertificateException on invalid data.
*/
private void setSerialNumber(Object val) throws CertificateException {
if (!(val instanceof CertificateSerialNumber)) {
throw new CertificateException("SerialNumber class type invalid.");
}
serialNum = (CertificateSerialNumber)val;
}
/**
* Set the algorithm id of the certificate.
*
* @params val the Object class value for the AlgorithmId
* @exception CertificateException on invalid data.
*/
private void setAlgorithmId(Object val) throws CertificateException {
if (!(val instanceof CertificateAlgorithmId)) {
throw new CertificateException(
"AlgorithmId class type invalid.");
}
algId = (CertificateAlgorithmId)val;
}
/**
* Set the issuer name of the certificate.
*
* @params val the Object class value for the issuer
* @exception CertificateException on invalid data.
*/
private void setIssuer(Object val) throws CertificateException {
if (!(val instanceof X500Name)) {
throw new CertificateException(
"Issuer class type invalid.");
}
issuer = (X500Name)val;
}
/**
* Set the validity interval of the certificate.
*
* @params val the Object class value for the CertificateValidity
* @exception CertificateException on invalid data.
*/
private void setValidity(Object val) throws CertificateException {
if (!(val instanceof CertificateValidity)) {
throw new CertificateException(
"CertificateValidity class type invalid.");
}
interval = (CertificateValidity)val;
}
/**
* Set the subject name of the certificate.
*
* @params val the Object class value for the Subject
* @exception CertificateException on invalid data.
*/
private void setSubject(Object val) throws CertificateException {
if (!(val instanceof X500Name)) {
throw new CertificateException(
"Subject class type invalid.");
}
subject = (X500Name)val;
}
/**
* Set the public key in the certificate.
*
* @params val the Object class value for the PublicKey
* @exception CertificateException on invalid data.
*/
private void setKey(Object val) throws CertificateException {
if (!(val instanceof CertificateX509Key)) {
throw new CertificateException(
"Key class type invalid.");
}
pubKey = (CertificateX509Key)val;
}
/**
* Set the Issuer Unique Identity in the certificate.
*
* @params val the Object class value for the IssuerUniqueId
* @exception CertificateException
*/
private void setIssuerUniqueId(Object val) throws CertificateException {
if (version.compare(CertificateVersion.V2) < 0) {
throw new CertificateException("Invalid version");
}
if (!(val instanceof UniqueIdentity)) {
throw new CertificateException(
"IssuerUniqueId class type invalid.");
}
issuerUniqueId = (UniqueIdentity)val;
}
/**
* Set the Subject Unique Identity in the certificate.
*
* @params val the Object class value for the SubjectUniqueId
* @exception CertificateException
*/
private void setSubjectUniqueId(Object val) throws CertificateException {
if (version.compare(CertificateVersion.V2) < 0) {
throw new CertificateException("Invalid version");
}
if (!(val instanceof UniqueIdentity)) {
throw new CertificateException(
"SubjectUniqueId class type invalid.");
}
subjectUniqueId = (UniqueIdentity)val;
}
/**
* Set the extensions in the certificate.
*
* @params val the Object class value for the Extensions
* @exception CertificateException
*/
private void setExtensions(Object val) throws CertificateException {
if (version.compare(CertificateVersion.V3) < 0) {
throw new CertificateException("Invalid version");
}
if (!(val instanceof CertificateExtensions)) {
throw new CertificateException(
"Extensions class type invalid.");
}
extensions = (CertificateExtensions)val;
}
}

View File

@@ -0,0 +1,476 @@
/*
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.x509;
import java.io.*;
import java.util.Arrays;
import java.util.Properties;
import java.security.Key;
import java.security.PublicKey;
import java.security.KeyFactory;
import java.security.Security;
import java.security.Provider;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import sun.misc.HexDumpEncoder;
import sun.security.util.*;
/**
* Holds an X.509 key, for example a public key found in an X.509
* certificate. Includes a description of the algorithm to be used
* with the key; these keys normally are used as
* "SubjectPublicKeyInfo".
*
* <P>While this class can represent any kind of X.509 key, it may be
* desirable to provide subclasses which understand how to parse keying
* data. For example, RSA public keys have two members, one for the
* public modulus and one for the prime exponent. If such a class is
* provided, it is used when parsing X.509 keys. If one is not provided,
* the key still parses correctly.
*
* @author David Brownell
*/
public class X509Key implements PublicKey {
/** use serialVersionUID from JDK 1.1. for interoperability */
private static final long serialVersionUID = -5359250853002055002L;
/* The algorithm information (name, parameters, etc). */
protected AlgorithmId algid;
/**
* The key bytes, without the algorithm information.
* @deprecated Use the BitArray form which does not require keys to
* be byte aligned.
* @see sun.security.x509.X509Key#setKey(BitArray)
* @see sun.security.x509.X509Key#getKey()
*/
@Deprecated
protected byte[] key = null;
/*
* The number of bits unused in the last byte of the key.
* Added to keep the byte[] key form consistent with the BitArray
* form. Can de deleted when byte[] key is deleted.
*/
@Deprecated
private int unusedBits = 0;
/* BitArray form of key */
private BitArray bitStringKey = null;
/* The encoding for the key. */
protected byte[] encodedKey;
/**
* Default constructor. The key constructed must have its key
* and algorithm initialized before it may be used, for example
* by using <code>decode</code>.
*/
public X509Key() { }
/*
* Build and initialize as a "default" key. All X.509 key
* data is stored and transmitted losslessly, but no knowledge
* about this particular algorithm is available.
*/
private X509Key(AlgorithmId algid, BitArray key)
throws InvalidKeyException {
this.algid = algid;
setKey(key);
encode();
}
/**
* Sets the key in the BitArray form.
*/
protected void setKey(BitArray key) {
this.bitStringKey = (BitArray)key.clone();
/*
* Do this to keep the byte array form consistent with
* this. Can delete when byte[] key is deleted.
*/
this.key = key.toByteArray();
int remaining = key.length() % 8;
this.unusedBits =
((remaining == 0) ? 0 : 8 - remaining);
}
/**
* Gets the key. The key may or may not be byte aligned.
* @return a BitArray containing the key.
*/
protected BitArray getKey() {
/*
* Do this for consistency in case a subclass
* modifies byte[] key directly. Remove when
* byte[] key is deleted.
* Note: the consistency checks fail when the subclass
* modifies a non byte-aligned key (into a byte-aligned key)
* using the deprecated byte[] key field.
*/
this.bitStringKey = new BitArray(
this.key.length * 8 - this.unusedBits,
this.key);
return (BitArray)bitStringKey.clone();
}
/**
* Construct X.509 subject public key from a DER value. If
* the runtime environment is configured with a specific class for
* this kind of key, a subclass is returned. Otherwise, a generic
* X509Key object is returned.
*
* <P>This mechanism gurantees that keys (and algorithms) may be
* freely manipulated and transferred, without risk of losing
* information. Also, when a key (or algorithm) needs some special
* handling, that specific need can be accomodated.
*
* @param in the DER-encoded SubjectPublicKeyInfo value
* @exception IOException on data format errors
*/
public static PublicKey parse(DerValue in) throws IOException
{
AlgorithmId algorithm;
PublicKey subjectKey;
if (in.tag != DerValue.tag_Sequence)
throw new IOException("corrupt subject key");
algorithm = AlgorithmId.parse(in.data.getDerValue());
try {
subjectKey = buildX509Key(algorithm,
in.data.getUnalignedBitString());
} catch (InvalidKeyException e) {
throw new IOException("subject key, " + e.getMessage(), e);
}
if (in.data.available() != 0)
throw new IOException("excess subject key");
return subjectKey;
}
/**
* Parse the key bits. This may be redefined by subclasses to take
* advantage of structure within the key. For example, RSA public
* keys encapsulate two unsigned integers (modulus and exponent) as
* DER values within the <code>key</code> bits; Diffie-Hellman and
* DSS/DSA keys encapsulate a single unsigned integer.
*
* <P>This function is called when creating X.509 SubjectPublicKeyInfo
* values using the X509Key member functions, such as <code>parse</code>
* and <code>decode</code>.
*
* @exception IOException on parsing errors.
* @exception InvalidKeyException on invalid key encodings.
*/
protected void parseKeyBits() throws IOException, InvalidKeyException {
encode();
}
/*
* Factory interface, building the kind of key associated with this
* specific algorithm ID or else returning this generic base class.
* See the description above.
*/
static PublicKey buildX509Key(AlgorithmId algid, BitArray key)
throws IOException, InvalidKeyException
{
/*
* Use the algid and key parameters to produce the ASN.1 encoding
* of the key, which will then be used as the input to the
* key factory.
*/
DerOutputStream x509EncodedKeyStream = new DerOutputStream();
encode(x509EncodedKeyStream, algid, key);
X509EncodedKeySpec x509KeySpec
= new X509EncodedKeySpec(x509EncodedKeyStream.toByteArray());
try {
// Instantiate the key factory of the appropriate algorithm
KeyFactory keyFac = KeyFactory.getInstance(algid.getName());
// Generate the public key
return keyFac.generatePublic(x509KeySpec);
} catch (NoSuchAlgorithmException e) {
// Return generic X509Key with opaque key data (see below)
} catch (InvalidKeySpecException e) {
throw new InvalidKeyException(e.getMessage(), e);
}
/*
* Try again using JDK1.1-style for backwards compatibility.
*/
String classname = "";
try {
Properties props;
String keytype;
Provider sunProvider;
sunProvider = Security.getProvider("SUN");
if (sunProvider == null)
throw new InstantiationException();
classname = sunProvider.getProperty("PublicKey.X.509." +
algid.getName());
if (classname == null) {
throw new InstantiationException();
}
Class<?> keyClass = null;
try {
keyClass = Class.forName(classname);
} catch (ClassNotFoundException e) {
ClassLoader cl = ClassLoader.getSystemClassLoader();
if (cl != null) {
keyClass = cl.loadClass(classname);
}
}
Object inst = null;
X509Key result;
if (keyClass != null)
inst = keyClass.newInstance();
if (inst instanceof X509Key) {
result = (X509Key) inst;
result.algid = algid;
result.setKey(key);
result.parseKeyBits();
return result;
}
} catch (ClassNotFoundException e) {
} catch (InstantiationException e) {
} catch (IllegalAccessException e) {
// this should not happen.
throw new IOException (classname + " [internal error]");
}
X509Key result = new X509Key(algid, key);
return result;
}
/**
* Returns the algorithm to be used with this key.
*/
public String getAlgorithm() {
return algid.getName();
}
/**
* Returns the algorithm ID to be used with this key.
*/
public AlgorithmId getAlgorithmId() { return algid; }
/**
* Encode SubjectPublicKeyInfo sequence on the DER output stream.
*
* @exception IOException on encoding errors.
*/
public final void encode(DerOutputStream out) throws IOException
{
encode(out, this.algid, getKey());
}
/**
* Returns the DER-encoded form of the key as a byte array.
*/
public byte[] getEncoded() {
try {
return getEncodedInternal().clone();
} catch (InvalidKeyException e) {
// XXX
}
return null;
}
public byte[] getEncodedInternal() throws InvalidKeyException {
byte[] encoded = encodedKey;
if (encoded == null) {
try {
DerOutputStream out = new DerOutputStream();
encode(out);
encoded = out.toByteArray();
} catch (IOException e) {
throw new InvalidKeyException("IOException : " +
e.getMessage());
}
encodedKey = encoded;
}
return encoded;
}
/**
* Returns the format for this key: "X.509"
*/
public String getFormat() {
return "X.509";
}
/**
* Returns the DER-encoded form of the key as a byte array.
*
* @exception InvalidKeyException on encoding errors.
*/
public byte[] encode() throws InvalidKeyException {
return getEncodedInternal().clone();
}
/*
* Returns a printable representation of the key
*/
public String toString()
{
HexDumpEncoder encoder = new HexDumpEncoder();
return "algorithm = " + algid.toString()
+ ", unparsed keybits = \n" + encoder.encodeBuffer(key);
}
/**
* Initialize an X509Key object from an input stream. The data on that
* input stream must be encoded using DER, obeying the X.509
* <code>SubjectPublicKeyInfo</code> format. That is, the data is a
* sequence consisting of an algorithm ID and a bit string which holds
* the key. (That bit string is often used to encapsulate another DER
* encoded sequence.)
*
* <P>Subclasses should not normally redefine this method; they should
* instead provide a <code>parseKeyBits</code> method to parse any
* fields inside the <code>key</code> member.
*
* <P>The exception to this rule is that since private keys need not
* be encoded using the X.509 <code>SubjectPublicKeyInfo</code> format,
* private keys may override this method, <code>encode</code>, and
* of course <code>getFormat</code>.
*
* @param in an input stream with a DER-encoded X.509
* SubjectPublicKeyInfo value
* @exception InvalidKeyException on parsing errors.
*/
public void decode(InputStream in)
throws InvalidKeyException
{
DerValue val;
try {
val = new DerValue(in);
if (val.tag != DerValue.tag_Sequence)
throw new InvalidKeyException("invalid key format");
algid = AlgorithmId.parse(val.data.getDerValue());
setKey(val.data.getUnalignedBitString());
parseKeyBits();
if (val.data.available() != 0)
throw new InvalidKeyException ("excess key data");
} catch (IOException e) {
throw new InvalidKeyException("IOException: " +
e.getMessage());
}
}
public void decode(byte[] encodedKey) throws InvalidKeyException {
decode(new ByteArrayInputStream(encodedKey));
}
/**
* Serialization write ... X.509 keys serialize as
* themselves, and they're parsed when they get read back.
*/
private void writeObject(ObjectOutputStream stream) throws IOException {
stream.write(getEncoded());
}
/**
* Serialization read ... X.509 keys serialize as
* themselves, and they're parsed when they get read back.
*/
private void readObject(ObjectInputStream stream) throws IOException {
try {
decode(stream);
} catch (InvalidKeyException e) {
e.printStackTrace();
throw new IOException("deserialized key is invalid: " +
e.getMessage());
}
}
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof Key == false) {
return false;
}
try {
byte[] thisEncoded = this.getEncodedInternal();
byte[] otherEncoded;
if (obj instanceof X509Key) {
otherEncoded = ((X509Key)obj).getEncodedInternal();
} else {
otherEncoded = ((Key)obj).getEncoded();
}
return Arrays.equals(thisEncoded, otherEncoded);
} catch (InvalidKeyException e) {
return false;
}
}
/**
* Calculates a hash code value for the object. Objects
* which are equal will also have the same hashcode.
*/
public int hashCode() {
try {
byte[] b1 = getEncodedInternal();
int r = b1.length;
for (int i = 0; i < b1.length; i++) {
r += (b1[i] & 0xff) * 37;
}
return r;
} catch (InvalidKeyException e) {
// should not happen
return 0;
}
}
/*
* Produce SubjectPublicKey encoding from algorithm id and key material.
*/
static void encode(DerOutputStream out, AlgorithmId algid, BitArray key)
throws IOException {
DerOutputStream tmp = new DerOutputStream();
algid.encode(tmp);
tmp.putUnalignedBitString(key);
out.write(DerValue.tag_Sequence, tmp);
}
}