1 /* 2 * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.security.pkcs; 27 28 import java.io.*; 29 30 import sun.security.util.*; 31 32 /** 33 * A ContentInfo type, as defined in PKCS#7. 34 * 35 * @author Benjamin Renaud 36 */ 37 public class ContentInfo { 38 39 // pkcs7 pre-defined content types 40 private static int[] pkcs7 = {1, 2, 840, 113549, 1, 7}; 41 private static int[] data = {1, 2, 840, 113549, 1, 7, 1}; 42 private static int[] sdata = {1, 2, 840, 113549, 1, 7, 2}; 43 private static int[] edata = {1, 2, 840, 113549, 1, 7, 3}; 44 private static int[] sedata = {1, 2, 840, 113549, 1, 7, 4}; 45 private static int[] ddata = {1, 2, 840, 113549, 1, 7, 5}; 46 private static int[] crdata = {1, 2, 840, 113549, 1, 7, 6}; 47 private static int[] nsdata = {2, 16, 840, 1, 113730, 2, 5}; 48 // timestamp token (id-ct-TSTInfo) from RFC 3161 49 private static int[] tstInfo = {1, 2, 840, 113549, 1, 9, 16, 1, 4}; 50 // this is for backwards-compatibility with JDK 1.1.x 51 private static final int[] OLD_SDATA = {1, 2, 840, 1113549, 1, 7, 2}; 52 private static final int[] OLD_DATA = {1, 2, 840, 1113549, 1, 7, 1}; 53 public static ObjectIdentifier PKCS7_OID; 54 public static ObjectIdentifier DATA_OID; 55 public static ObjectIdentifier SIGNED_DATA_OID; 56 public static ObjectIdentifier ENVELOPED_DATA_OID; 57 public static ObjectIdentifier SIGNED_AND_ENVELOPED_DATA_OID; 58 public static ObjectIdentifier DIGESTED_DATA_OID; 59 public static ObjectIdentifier ENCRYPTED_DATA_OID; 60 public static ObjectIdentifier OLD_SIGNED_DATA_OID; 61 public static ObjectIdentifier OLD_DATA_OID; 62 public static ObjectIdentifier NETSCAPE_CERT_SEQUENCE_OID; 63 public static ObjectIdentifier TIMESTAMP_TOKEN_INFO_OID; 64 65 static { 66 PKCS7_OID = ObjectIdentifier.newInternal(pkcs7); 67 DATA_OID = ObjectIdentifier.newInternal(data); 68 SIGNED_DATA_OID = ObjectIdentifier.newInternal(sdata); 69 ENVELOPED_DATA_OID = ObjectIdentifier.newInternal(edata); 70 SIGNED_AND_ENVELOPED_DATA_OID = ObjectIdentifier.newInternal(sedata); 71 DIGESTED_DATA_OID = ObjectIdentifier.newInternal(ddata); 72 ENCRYPTED_DATA_OID = ObjectIdentifier.newInternal(crdata); 73 OLD_SIGNED_DATA_OID = ObjectIdentifier.newInternal(OLD_SDATA); 74 OLD_DATA_OID = ObjectIdentifier.newInternal(OLD_DATA); 75 /** 76 * The ASN.1 systax for the Netscape Certificate Sequence 77 * data type is defined 78 * <a href=http://wp.netscape.com/eng/security/comm4-cert-download.html> 79 * here.</a> 80 */ 81 NETSCAPE_CERT_SEQUENCE_OID = ObjectIdentifier.newInternal(nsdata); 82 TIMESTAMP_TOKEN_INFO_OID = ObjectIdentifier.newInternal(tstInfo); 83 } 84 85 ObjectIdentifier contentType; 86 DerValue content; // OPTIONAL 87 ContentInfo(ObjectIdentifier contentType, DerValue content)88 public ContentInfo(ObjectIdentifier contentType, DerValue content) { 89 this.contentType = contentType; 90 this.content = content; 91 } 92 93 /** 94 * Make a contentInfo of type data. 95 */ ContentInfo(byte[] bytes)96 public ContentInfo(byte[] bytes) { 97 DerValue octetString = new DerValue(DerValue.tag_OctetString, bytes); 98 this.contentType = DATA_OID; 99 this.content = octetString; 100 } 101 102 /** 103 * Parses a PKCS#7 content info. 104 */ ContentInfo(DerInputStream derin)105 public ContentInfo(DerInputStream derin) 106 throws IOException, ParsingException 107 { 108 this(derin, false); 109 } 110 111 /** 112 * Parses a PKCS#7 content info. 113 * 114 * <p>This constructor is used only for backwards compatibility with 115 * PKCS#7 blocks that were generated using JDK1.1.x. 116 * 117 * @param derin the ASN.1 encoding of the content info. 118 * @param oldStyle flag indicating whether or not the given content info 119 * is encoded according to JDK1.1.x. 120 */ ContentInfo(DerInputStream derin, boolean oldStyle)121 public ContentInfo(DerInputStream derin, boolean oldStyle) 122 throws IOException, ParsingException 123 { 124 DerInputStream disType; 125 DerInputStream disTaggedContent; 126 DerValue type; 127 DerValue taggedContent; 128 DerValue[] typeAndContent; 129 DerValue[] contents; 130 131 typeAndContent = derin.getSequence(2); 132 133 // Parse the content type 134 type = typeAndContent[0]; 135 disType = new DerInputStream(type.toByteArray()); 136 contentType = disType.getOID(); 137 138 if (oldStyle) { 139 // JDK1.1.x-style encoding 140 content = typeAndContent[1]; 141 } else { 142 // This is the correct, standards-compliant encoding. 143 // Parse the content (OPTIONAL field). 144 // Skip the [0] EXPLICIT tag by pretending that the content is the 145 // one and only element in an implicitly tagged set 146 if (typeAndContent.length > 1) { // content is OPTIONAL 147 taggedContent = typeAndContent[1]; 148 disTaggedContent 149 = new DerInputStream(taggedContent.toByteArray()); 150 contents = disTaggedContent.getSet(1, true); 151 content = contents[0]; 152 } 153 } 154 } 155 getContent()156 public DerValue getContent() { 157 return content; 158 } 159 getContentType()160 public ObjectIdentifier getContentType() { 161 return contentType; 162 } 163 getData()164 public byte[] getData() throws IOException { 165 if (contentType.equals((Object)DATA_OID) || 166 contentType.equals((Object)OLD_DATA_OID) || 167 contentType.equals((Object)TIMESTAMP_TOKEN_INFO_OID)) { 168 if (content == null) 169 return null; 170 else 171 return content.getOctetString(); 172 } 173 throw new IOException("content type is not DATA: " + contentType); 174 } 175 encode(DerOutputStream out)176 public void encode(DerOutputStream out) throws IOException { 177 DerOutputStream contentDerCode; 178 DerOutputStream seq; 179 180 seq = new DerOutputStream(); 181 seq.putOID(contentType); 182 183 // content is optional, it could be external 184 if (content != null) { 185 DerValue taggedContent = null; 186 contentDerCode = new DerOutputStream(); 187 content.encode(contentDerCode); 188 189 // Add the [0] EXPLICIT tag in front of the content encoding 190 taggedContent = new DerValue((byte)0xA0, 191 contentDerCode.toByteArray()); 192 seq.putDerValue(taggedContent); 193 } 194 195 out.write(DerValue.tag_Sequence, seq); 196 } 197 198 /** 199 * Returns a byte array representation of the data held in 200 * the content field. 201 * @return byte array representation of data held in content field 202 * @throws IOException if content bytes are invalid 203 */ getContentBytes()204 public byte[] getContentBytes() throws IOException { 205 if (content == null) 206 return null; 207 208 DerInputStream dis = new DerInputStream(content.toByteArray()); 209 return dis.getOctetString(); 210 } 211 toString()212 public String toString() { 213 String out = ""; 214 215 out += "Content Info Sequence\n\tContent type: " + contentType + "\n"; 216 out += "\tContent: " + content; 217 return out; 218 } 219 } 220