Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/provider/certpath/X509CertPath.java
38923 views
/*1* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.security.provider.certpath;2627import java.io.ByteArrayInputStream;28import java.io.ByteArrayOutputStream;29import java.io.IOException;30import java.io.InputStream;31import java.security.cert.CertificateEncodingException;32import java.security.cert.Certificate;33import java.security.cert.CertificateException;34import java.security.cert.CertificateFactory;35import java.security.cert.CertPath;36import java.security.cert.X509Certificate;37import java.util.*;3839import sun.security.pkcs.ContentInfo;40import sun.security.pkcs.PKCS7;41import sun.security.pkcs.SignerInfo;42import sun.security.x509.AlgorithmId;43import sun.security.util.DerValue;44import sun.security.util.DerOutputStream;45import sun.security.util.DerInputStream;4647/**48* A {@link java.security.cert.CertPath CertPath} (certification path)49* consisting exclusively of50* {@link java.security.cert.X509Certificate X509Certificate}s.51* <p>52* By convention, X.509 <code>CertPath</code>s are stored from target53* to trust anchor.54* That is, the issuer of one certificate is the subject of the following55* one. However, unvalidated X.509 <code>CertPath</code>s may not follow56* this convention. PKIX <code>CertPathValidator</code>s will detect any57* departure from this convention and throw a58* <code>CertPathValidatorException</code>.59*60* @author Yassir Elley61* @since 1.462*/63public class X509CertPath extends CertPath {6465private static final long serialVersionUID = 4989800333263052980L;6667/**68* List of certificates in this chain69*/70private List<X509Certificate> certs;7172/**73* The names of our encodings. PkiPath is the default.74*/75private static final String COUNT_ENCODING = "count";76private static final String PKCS7_ENCODING = "PKCS7";77private static final String PKIPATH_ENCODING = "PkiPath";7879/**80* List of supported encodings81*/82private static final Collection<String> encodingList;8384static {85List<String> list = new ArrayList<>(2);86list.add(PKIPATH_ENCODING);87list.add(PKCS7_ENCODING);88encodingList = Collections.unmodifiableCollection(list);89}9091/**92* Creates an <code>X509CertPath</code> from a <code>List</code> of93* <code>X509Certificate</code>s.94* <p>95* The certificates are copied out of the supplied <code>List</code>96* object.97*98* @param certs a <code>List</code> of <code>X509Certificate</code>s99* @exception CertificateException if <code>certs</code> contains an element100* that is not an <code>X509Certificate</code>101*/102@SuppressWarnings("unchecked")103public X509CertPath(List<? extends Certificate> certs) throws CertificateException {104super("X.509");105106// Ensure that the List contains only X509Certificates107//108// Note; The certs parameter is not necessarily to be of Certificate109// for some old code. For compatibility, to make sure the exception110// is CertificateException, rather than ClassCastException, please111// don't use112// for (Certificate obj : certs)113for (Object obj : certs) {114if (obj instanceof X509Certificate == false) {115throw new CertificateException116("List is not all X509Certificates: "117+ obj.getClass().getName());118}119}120121// Assumes that the resulting List is thread-safe. This is true122// because we ensure that it cannot be modified after construction123// and the methods in the Sun JDK 1.4 implementation of ArrayList that124// allow read-only access are thread-safe.125this.certs = Collections.unmodifiableList(126new ArrayList<X509Certificate>((List<X509Certificate>)certs));127}128129/**130* Creates an <code>X509CertPath</code>, reading the encoded form131* from an <code>InputStream</code>. The data is assumed to be in132* the default encoding.133*134* @param is the <code>InputStream</code> to read the data from135* @exception CertificateException if an exception occurs while decoding136*/137public X509CertPath(InputStream is) throws CertificateException {138this(is, PKIPATH_ENCODING);139}140141/**142* Creates an <code>X509CertPath</code>, reading the encoded form143* from an InputStream. The data is assumed to be in the specified144* encoding.145*146* @param is the <code>InputStream</code> to read the data from147* @param encoding the encoding used148* @exception CertificateException if an exception occurs while decoding or149* the encoding requested is not supported150*/151public X509CertPath(InputStream is, String encoding)152throws CertificateException {153super("X.509");154155switch (encoding) {156case PKIPATH_ENCODING:157certs = parsePKIPATH(is);158break;159case PKCS7_ENCODING:160certs = parsePKCS7(is);161break;162default:163throw new CertificateException("unsupported encoding");164}165}166167/**168* Parse a PKIPATH format CertPath from an InputStream. Return an169* unmodifiable List of the certificates.170*171* @param is the <code>InputStream</code> to read the data from172* @return an unmodifiable List of the certificates173* @exception CertificateException if an exception occurs174*/175private static List<X509Certificate> parsePKIPATH(InputStream is)176throws CertificateException {177List<X509Certificate> certList = null;178CertificateFactory certFac = null;179180if (is == null) {181throw new CertificateException("input stream is null");182}183184try {185DerInputStream dis = new DerInputStream(readAllBytes(is));186DerValue[] seq = dis.getSequence(3);187if (seq.length == 0) {188return Collections.<X509Certificate>emptyList();189}190191certFac = CertificateFactory.getInstance("X.509");192certList = new ArrayList<X509Certificate>(seq.length);193194// append certs in reverse order (target to trust anchor)195for (int i = seq.length-1; i >= 0; i--) {196certList.add((X509Certificate)certFac.generateCertificate197(new ByteArrayInputStream(seq[i].toByteArray())));198}199200return Collections.unmodifiableList(certList);201202} catch (IOException ioe) {203throw new CertificateException("IOException parsing PkiPath data: "204+ ioe, ioe);205}206}207208/**209* Parse a PKCS#7 format CertPath from an InputStream. Return an210* unmodifiable List of the certificates.211*212* @param is the <code>InputStream</code> to read the data from213* @return an unmodifiable List of the certificates214* @exception CertificateException if an exception occurs215*/216private static List<X509Certificate> parsePKCS7(InputStream is)217throws CertificateException {218List<X509Certificate> certList;219220if (is == null) {221throw new CertificateException("input stream is null");222}223224try {225if (is.markSupported() == false) {226// Copy the entire input stream into an InputStream that does227// support mark228is = new ByteArrayInputStream(readAllBytes(is));229}230PKCS7 pkcs7 = new PKCS7(is);231232X509Certificate[] certArray = pkcs7.getCertificates();233// certs are optional in PKCS #7234if (certArray != null) {235certList = Arrays.asList(certArray);236} else {237// no certs provided238certList = new ArrayList<X509Certificate>(0);239}240} catch (IOException ioe) {241throw new CertificateException("IOException parsing PKCS7 data: " +242ioe);243}244// Assumes that the resulting List is thread-safe. This is true245// because we ensure that it cannot be modified after construction246// and the methods in the Sun JDK 1.4 implementation of ArrayList that247// allow read-only access are thread-safe.248return Collections.unmodifiableList(certList);249}250251/*252* Reads the entire contents of an InputStream into a byte array.253*254* @param is the InputStream to read from255* @return the bytes read from the InputStream256*/257private static byte[] readAllBytes(InputStream is) throws IOException {258byte[] buffer = new byte[8192];259ByteArrayOutputStream baos = new ByteArrayOutputStream(2048);260int n;261while ((n = is.read(buffer)) != -1) {262baos.write(buffer, 0, n);263}264return baos.toByteArray();265}266267/**268* Returns the encoded form of this certification path, using the269* default encoding.270*271* @return the encoded bytes272* @exception CertificateEncodingException if an encoding error occurs273*/274@Override275public byte[] getEncoded() throws CertificateEncodingException {276// @@@ Should cache the encoded form277return encodePKIPATH();278}279280/**281* Encode the CertPath using PKIPATH format.282*283* @return a byte array containing the binary encoding of the PkiPath object284* @exception CertificateEncodingException if an exception occurs285*/286private byte[] encodePKIPATH() throws CertificateEncodingException {287288ListIterator<X509Certificate> li = certs.listIterator(certs.size());289try {290DerOutputStream bytes = new DerOutputStream();291// encode certs in reverse order (trust anchor to target)292// according to PkiPath format293while (li.hasPrevious()) {294X509Certificate cert = li.previous();295// check for duplicate cert296if (certs.lastIndexOf(cert) != certs.indexOf(cert)) {297throw new CertificateEncodingException298("Duplicate Certificate");299}300// get encoded certificates301byte[] encoded = cert.getEncoded();302bytes.write(encoded);303}304305// Wrap the data in a SEQUENCE306DerOutputStream derout = new DerOutputStream();307derout.write(DerValue.tag_SequenceOf, bytes);308return derout.toByteArray();309310} catch (IOException ioe) {311throw new CertificateEncodingException("IOException encoding " +312"PkiPath data: " + ioe, ioe);313}314}315316/**317* Encode the CertPath using PKCS#7 format.318*319* @return a byte array containing the binary encoding of the PKCS#7 object320* @exception CertificateEncodingException if an exception occurs321*/322private byte[] encodePKCS7() throws CertificateEncodingException {323PKCS7 p7 = new PKCS7(new AlgorithmId[0],324new ContentInfo(ContentInfo.DATA_OID, null),325certs.toArray(new X509Certificate[certs.size()]),326new SignerInfo[0]);327DerOutputStream derout = new DerOutputStream();328try {329p7.encodeSignedData(derout);330} catch (IOException ioe) {331throw new CertificateEncodingException(ioe.getMessage());332}333return derout.toByteArray();334}335336/**337* Returns the encoded form of this certification path, using the338* specified encoding.339*340* @param encoding the name of the encoding to use341* @return the encoded bytes342* @exception CertificateEncodingException if an encoding error occurs or343* the encoding requested is not supported344*/345@Override346public byte[] getEncoded(String encoding)347throws CertificateEncodingException {348switch (encoding) {349case PKIPATH_ENCODING:350return encodePKIPATH();351case PKCS7_ENCODING:352return encodePKCS7();353default:354throw new CertificateEncodingException("unsupported encoding");355}356}357358/**359* Returns the encodings supported by this certification path, with the360* default encoding first.361*362* @return an <code>Iterator</code> over the names of the supported363* encodings (as Strings)364*/365public static Iterator<String> getEncodingsStatic() {366return encodingList.iterator();367}368369/**370* Returns an iteration of the encodings supported by this certification371* path, with the default encoding first.372* <p>373* Attempts to modify the returned <code>Iterator</code> via its374* <code>remove</code> method result in an375* <code>UnsupportedOperationException</code>.376*377* @return an <code>Iterator</code> over the names of the supported378* encodings (as Strings)379*/380@Override381public Iterator<String> getEncodings() {382return getEncodingsStatic();383}384385/**386* Returns the list of certificates in this certification path.387* The <code>List</code> returned must be immutable and thread-safe.388*389* @return an immutable <code>List</code> of <code>X509Certificate</code>s390* (may be empty, but not null)391*/392@Override393public List<X509Certificate> getCertificates() {394return certs;395}396}397398399