Path: blob/master/src/java.base/share/classes/sun/security/pkcs/PKCS9Attributes.java
41159 views
/*1* Copyright (c) 1997, 2006, 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.pkcs;2627import java.io.IOException;28import java.io.OutputStream;29import java.util.Hashtable;30import sun.security.util.DerEncoder;31import sun.security.util.DerValue;32import sun.security.util.DerInputStream;33import sun.security.util.DerOutputStream;34import sun.security.util.ObjectIdentifier;3536/**37* A set of attributes of class PKCS9Attribute.38*39* @author Douglas Hoover40*/41public class PKCS9Attributes {42/**43* Attributes in this set indexed by OID.44*/45private final Hashtable<ObjectIdentifier, PKCS9Attribute> attributes =46new Hashtable<ObjectIdentifier, PKCS9Attribute>(3);4748/**49* The keys of this hashtable are the OIDs of permitted attributes.50*/51private final Hashtable<ObjectIdentifier, ObjectIdentifier> permittedAttributes;5253/**54* The DER encoding of this attribute set. The tag byte must be55* DerValue.tag_SetOf.56*/57private final byte[] derEncoding;5859/*60* Contols how attributes, which are not recognized by the PKCS9Attribute61* class, are handled during parsing.62*/63private boolean ignoreUnsupportedAttributes = false;6465/**66* Construct a set of PKCS9 Attributes from its67* DER encoding on a DerInputStream, accepting only attributes68* with OIDs on the given69* list. If the array is null, accept all attributes supported by70* class PKCS9Attribute.71*72* @param permittedAttributes73* Array of attribute OIDs that will be accepted.74* @param in75* the contents of the DER encoding of the attribute set.76*77* @exception IOException78* on i/o error, encoding syntax error, unacceptable or79* unsupported attribute, or duplicate attribute.80*81* @see PKCS9Attribute82*/83public PKCS9Attributes(ObjectIdentifier[] permittedAttributes,84DerInputStream in) throws IOException {85if (permittedAttributes != null) {86this.permittedAttributes =87new Hashtable<>(permittedAttributes.length);8889for (int i = 0; i < permittedAttributes.length; i++)90this.permittedAttributes.put(permittedAttributes[i],91permittedAttributes[i]);92} else {93this.permittedAttributes = null;94}9596// derEncoding initialized in <code>decode()</code>97derEncoding = decode(in);98}99100/**101* Construct a set of PKCS9 Attributes from the contents of its102* DER encoding on a DerInputStream. Accept all attributes103* supported by class PKCS9Attribute and reject any unsupported104* attributes.105*106* @param in the contents of the DER encoding of the attribute set.107* @exception IOException108* on i/o error, encoding syntax error, or unsupported or109* duplicate attribute.110*111* @see PKCS9Attribute112*/113public PKCS9Attributes(DerInputStream in) throws IOException {114this(in, false);115}116117/**118* Construct a set of PKCS9 Attributes from the contents of its119* DER encoding on a DerInputStream. Accept all attributes120* supported by class PKCS9Attribute and ignore any unsupported121* attributes, if directed.122*123* @param in the contents of the DER encoding of the attribute set.124* @param ignoreUnsupportedAttributes If true then any attributes125* not supported by the PKCS9Attribute class are ignored. Otherwise126* unsupported attributes cause an exception to be thrown.127* @exception IOException128* on i/o error, encoding syntax error, or unsupported or129* duplicate attribute.130*131* @see PKCS9Attribute132*/133public PKCS9Attributes(DerInputStream in,134boolean ignoreUnsupportedAttributes) throws IOException {135136this.ignoreUnsupportedAttributes = ignoreUnsupportedAttributes;137// derEncoding initialized in <code>decode()</code>138derEncoding = decode(in);139permittedAttributes = null;140}141142/**143* Construct a set of PKCS9 Attributes from the given array of144* PKCS9 attributes.145* DER encoding on a DerInputStream. All attributes in146* <code>attribs</code> must be147* supported by class PKCS9Attribute.148*149* @exception IOException150* on i/o error, encoding syntax error, or unsupported or151* duplicate attribute.152*153* @see PKCS9Attribute154*/155public PKCS9Attributes(PKCS9Attribute[] attribs)156throws IllegalArgumentException, IOException {157ObjectIdentifier oid;158for (int i=0; i < attribs.length; i++) {159oid = attribs[i].getOID();160if (attributes.containsKey(oid))161throw new IllegalArgumentException(162"PKCSAttribute " + attribs[i].getOID() +163" duplicated while constructing " +164"PKCS9Attributes.");165166attributes.put(oid, attribs[i]);167}168derEncoding = generateDerEncoding();169permittedAttributes = null;170}171172173/**174* Decode this set of PKCS9 attributes from the contents of its175* DER encoding. Ignores unsupported attributes when directed.176*177* @param in178* the contents of the DER encoding of the attribute set.179*180* @exception IOException181* on i/o error, encoding syntax error, unacceptable or182* unsupported attribute, or duplicate attribute.183*/184private byte[] decode(DerInputStream in) throws IOException {185186DerValue val = in.getDerValue();187188// save the DER encoding with its proper tag byte.189byte[] derEncoding = val.toByteArray();190derEncoding[0] = DerValue.tag_SetOf;191192DerInputStream derIn = new DerInputStream(derEncoding);193DerValue[] derVals = derIn.getSet(3,true);194195PKCS9Attribute attrib;196ObjectIdentifier oid;197boolean reuseEncoding = true;198199for (int i=0; i < derVals.length; i++) {200201try {202attrib = new PKCS9Attribute(derVals[i]);203204} catch (ParsingException e) {205if (ignoreUnsupportedAttributes) {206reuseEncoding = false; // cannot reuse supplied DER encoding207continue; // skip208} else {209throw e;210}211}212oid = attrib.getOID();213214if (attributes.get(oid) != null)215throw new IOException("Duplicate PKCS9 attribute: " + oid);216217if (permittedAttributes != null &&218!permittedAttributes.containsKey(oid))219throw new IOException("Attribute " + oid +220" not permitted in this attribute set");221222attributes.put(oid, attrib);223}224return reuseEncoding ? derEncoding : generateDerEncoding();225}226227/**228* Put the DER encoding of this PKCS9 attribute set on an229* DerOutputStream, tagged with the given implicit tag.230*231* @param tag the implicit tag to use in the DER encoding.232* @param out the output stream on which to put the DER encoding.233*234* @exception IOException on output error.235*/236public void encode(byte tag, OutputStream out) throws IOException {237out.write(tag);238out.write(derEncoding, 1, derEncoding.length -1);239}240241private byte[] generateDerEncoding() throws IOException {242DerOutputStream out = new DerOutputStream();243Object[] attribVals = attributes.values().toArray();244245out.putOrderedSetOf(DerValue.tag_SetOf,246castToDerEncoder(attribVals));247return out.toByteArray();248}249250/**251* Return the DER encoding of this attribute set, tagged with252* DerValue.tag_SetOf.253*/254public byte[] getDerEncoding() throws IOException {255return derEncoding.clone();256257}258259/**260* Get an attribute from this set.261*/262public PKCS9Attribute getAttribute(ObjectIdentifier oid) {263return attributes.get(oid);264}265266/**267* Get an attribute from this set.268*/269public PKCS9Attribute getAttribute(String name) {270return attributes.get(PKCS9Attribute.getOID(name));271}272273274/**275* Get an array of all attributes in this set, in order of OID.276*/277public PKCS9Attribute[] getAttributes() {278PKCS9Attribute[] attribs = new PKCS9Attribute[attributes.size()];279ObjectIdentifier oid;280281int j = 0;282for (int i=1; i < PKCS9Attribute.PKCS9_OIDS.length &&283j < attribs.length; i++) {284attribs[j] = getAttribute(PKCS9Attribute.PKCS9_OIDS[i]);285286if (attribs[j] != null)287j++;288}289return attribs;290}291292/**293* Get an attribute value by OID.294*/295public Object getAttributeValue(ObjectIdentifier oid)296throws IOException {297try {298Object value = getAttribute(oid).getValue();299return value;300} catch (NullPointerException ex) {301throw new IOException("No value found for attribute " + oid);302}303304}305306/**307* Get an attribute value by type name.308*/309public Object getAttributeValue(String name) throws IOException {310ObjectIdentifier oid = PKCS9Attribute.getOID(name);311312if (oid == null)313throw new IOException("Attribute name " + name +314" not recognized or not supported.");315316return getAttributeValue(oid);317}318319320/**321* Returns the PKCS9 block in a printable string form.322*/323public String toString() {324StringBuilder sb = new StringBuilder(200);325sb.append("PKCS9 Attributes: [\n\t");326327ObjectIdentifier oid;328PKCS9Attribute value;329330boolean first = true;331for (int i = 1; i < PKCS9Attribute.PKCS9_OIDS.length; i++) {332value = getAttribute(PKCS9Attribute.PKCS9_OIDS[i]);333334if (value == null) continue;335336// we have a value; print it337if (first)338first = false;339else340sb.append(";\n\t");341342sb.append(value.toString());343}344345sb.append("\n\t] (end PKCS9 Attributes)");346347return sb.toString();348}349350/**351* Cast an object array whose components are352* <code>DerEncoder</code>s to <code>DerEncoder[]</code>.353*/354static DerEncoder[] castToDerEncoder(Object[] objs) {355356DerEncoder[] encoders = new DerEncoder[objs.length];357358for (int i=0; i < encoders.length; i++)359encoders[i] = (DerEncoder) objs[i];360361return encoders;362}363}364365366