View Javadoc
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  
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       */
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      */
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      */
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 
157     public DerValue getContent() {
158         return content;
159     }
160 
161     public ObjectIdentifier getContentType() {
162         return contentType;
163     }
164 
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 
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      */
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 
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 }