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