1 /* 2 * Copyright (c) 1996, 2005, 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 38 public class ContentInfo { 39 40 // pkcs7 pre-defined content types 41 private static int[] pkcs7 = {1, 2, 840, 113549, 1, 7}; 42 private static int[] data = {1, 2, 840, 113549, 1, 7, 1}; 43 private static int[] sdata = {1, 2, 840, 113549, 1, 7, 2}; 44 private static int[] edata = {1, 2, 840, 113549, 1, 7, 3}; 45 private static int[] sedata = {1, 2, 840, 113549, 1, 7, 4}; 46 private static int[] ddata = {1, 2, 840, 113549, 1, 7, 5}; 47 private static int[] crdata = {1, 2, 840, 113549, 1, 7, 6}; 48 private static int[] nsdata = {2, 16, 840, 1, 113730, 2, 5}; 49 // timestamp token (id-ct-TSTInfo) from RFC 3161 50 private static int[] tstInfo = {1, 2, 840, 113549, 1, 9, 16, 1, 4}; 51 // this is for backwards-compatibility with JDK 1.1.x 52 private static final int[] OLD_SDATA = {1, 2, 840, 1113549, 1, 7, 2}; 53 private static final int[] OLD_DATA = {1, 2, 840, 1113549, 1, 7, 1}; 54 public static ObjectIdentifier PKCS7_OID; 55 public static ObjectIdentifier DATA_OID; 56 public static ObjectIdentifier SIGNED_DATA_OID; 57 public static ObjectIdentifier ENVELOPED_DATA_OID; 58 public static ObjectIdentifier SIGNED_AND_ENVELOPED_DATA_OID; 59 public static ObjectIdentifier DIGESTED_DATA_OID; 60 public static ObjectIdentifier ENCRYPTED_DATA_OID; 61 public static ObjectIdentifier OLD_SIGNED_DATA_OID; 62 public static ObjectIdentifier OLD_DATA_OID; 63 public static ObjectIdentifier NETSCAPE_CERT_SEQUENCE_OID; 64 public static ObjectIdentifier TIMESTAMP_TOKEN_INFO_OID; 65 66 static { 67 PKCS7_OID = ObjectIdentifier.newInternal(pkcs7); 68 DATA_OID = ObjectIdentifier.newInternal(data); 69 SIGNED_DATA_OID = ObjectIdentifier.newInternal(sdata); 70 ENVELOPED_DATA_OID = ObjectIdentifier.newInternal(edata); 71 SIGNED_AND_ENVELOPED_DATA_OID = ObjectIdentifier.newInternal(sedata); 72 DIGESTED_DATA_OID = ObjectIdentifier.newInternal(ddata); 73 ENCRYPTED_DATA_OID = ObjectIdentifier.newInternal(crdata); 74 OLD_SIGNED_DATA_OID = ObjectIdentifier.newInternal(OLD_SDATA); 75 OLD_DATA_OID = ObjectIdentifier.newInternal(OLD_DATA); 76 /** 77 * The ASN.1 systax for the Netscape Certificate Sequence 78 * data type is defined 79 * <a href=http://wp.netscape.com/eng/security/comm4-cert-download.html> 80 * here.</a> 81 */ 82 NETSCAPE_CERT_SEQUENCE_OID = ObjectIdentifier.newInternal(nsdata); 83 TIMESTAMP_TOKEN_INFO_OID = ObjectIdentifier.newInternal(tstInfo); 84 } 85 86 ObjectIdentifier contentType; 87 DerValue content; // OPTIONAL 88 ContentInfo(ObjectIdentifier contentType, DerValue content)89 public ContentInfo(ObjectIdentifier contentType, DerValue content) { 90 this.contentType = contentType; 91 this.content = content; 92 } 93 94 /** 95 * Make a contentInfo of type data. 96 */ ContentInfo(byte[] bytes)97 public ContentInfo(byte[] bytes) { 98 DerValue octetString = new DerValue(DerValue.tag_OctetString, bytes); 99 this.contentType = DATA_OID; 100 this.content = octetString; 101 } 102 103 /** 104 * Parses a PKCS#7 content info. 105 */ ContentInfo(DerInputStream derin)106 public ContentInfo(DerInputStream derin) 107 throws IOException, ParsingException 108 { 109 this(derin, false); 110 } 111 112 /** 113 * Parses a PKCS#7 content info. 114 * 115 * <p>This constructor is used only for backwards compatibility with 116 * PKCS#7 blocks that were generated using JDK1.1.x. 117 * 118 * @param derin the ASN.1 encoding of the content info. 119 * @param oldStyle flag indicating whether or not the given content info 120 * is encoded according to JDK1.1.x. 121 */ ContentInfo(DerInputStream derin, boolean oldStyle)122 public ContentInfo(DerInputStream derin, boolean oldStyle) 123 throws IOException, ParsingException 124 { 125 DerInputStream disType; 126 DerInputStream disTaggedContent; 127 DerValue type; 128 DerValue taggedContent; 129 DerValue[] typeAndContent; 130 DerValue[] contents; 131 132 typeAndContent = derin.getSequence(2); 133 134 // Parse the content type 135 type = typeAndContent[0]; 136 disType = new DerInputStream(type.toByteArray()); 137 contentType = disType.getOID(); 138 139 if (oldStyle) { 140 // JDK1.1.x-style encoding 141 content = typeAndContent[1]; 142 } else { 143 // This is the correct, standards-compliant encoding. 144 // Parse the content (OPTIONAL field). 145 // Skip the [0] EXPLICIT tag by pretending that the content is the 146 // one and only element in an implicitly tagged set 147 if (typeAndContent.length > 1) { // content is OPTIONAL 148 taggedContent = typeAndContent[1]; 149 disTaggedContent 150 = new DerInputStream(taggedContent.toByteArray()); 151 contents = disTaggedContent.getSet(1, true); 152 content = contents[0]; 153 } 154 } 155 } 156 getContent()157 public DerValue getContent() { 158 return content; 159 } 160 getContentType()161 public ObjectIdentifier getContentType() { 162 return contentType; 163 } 164 getData()165 public byte[] getData() throws IOException { 166 if (contentType.equals(DATA_OID) || 167 contentType.equals(OLD_DATA_OID) || 168 contentType.equals(TIMESTAMP_TOKEN_INFO_OID)) { 169 if (content == null) 170 return null; 171 else 172 return content.getOctetString(); 173 } 174 throw new IOException("content type is not DATA: " + contentType); 175 } 176 encode(DerOutputStream out)177 public void encode(DerOutputStream out) throws IOException { 178 DerOutputStream contentDerCode; 179 DerOutputStream seq; 180 181 seq = new DerOutputStream(); 182 seq.putOID(contentType); 183 184 // content is optional, it could be external 185 if (content != null) { 186 DerValue taggedContent = null; 187 contentDerCode = new DerOutputStream(); 188 content.encode(contentDerCode); 189 190 // Add the [0] EXPLICIT tag in front of the content encoding 191 taggedContent = new DerValue((byte)0xA0, 192 contentDerCode.toByteArray()); 193 seq.putDerValue(taggedContent); 194 } 195 196 out.write(DerValue.tag_Sequence, seq); 197 } 198 199 /** 200 * Returns a byte array representation of the data held in 201 * the content field. 202 */ getContentBytes()203 public byte[] getContentBytes() throws IOException { 204 if (content == null) 205 return null; 206 207 DerInputStream dis = new DerInputStream(content.toByteArray()); 208 return dis.getOctetString(); 209 } 210 toString()211 public String toString() { 212 String out = ""; 213 214 out += "Content Info Sequence\n\tContent type: " + contentType + "\n"; 215 out += "\tContent: " + content; 216 return out; 217 } 218 } 219