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 
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((Object)DATA_OID) ||
167             contentType.equals((Object)OLD_DATA_OID) ||
168             contentType.equals((Object)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