ContentInfo.java revision 7365de1056414750d0a7d1fdd26025fd247f0d04
1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18/**
19* @author Boris Kuznetsov
20* @version $Revision$
21*/
22package org.apache.harmony.security.pkcs7;
23
24import java.io.IOException;
25import java.util.Arrays;
26import org.apache.harmony.security.asn1.ASN1Any;
27import org.apache.harmony.security.asn1.ASN1Explicit;
28import org.apache.harmony.security.asn1.ASN1OctetString;
29import org.apache.harmony.security.asn1.ASN1Oid;
30import org.apache.harmony.security.asn1.ASN1Sequence;
31import org.apache.harmony.security.asn1.ASN1Type;
32import org.apache.harmony.security.asn1.BerInputStream;
33
34/**
35 * As defined in PKCS #7: Cryptographic Message Syntax Standard
36 * (http://www.ietf.org/rfc/rfc2315.txt)
37 *
38 * ContentInfo ::= SEQUENCE {
39 *       contentType  ContentType,
40 *       content      [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL
41 *     }
42 */
43
44public class ContentInfo {
45
46    // OIDs
47    public static final int[] DATA = new int[] {1, 2, 840, 113549, 1, 7, 1};
48    public static final int[] SIGNED_DATA = new int[] {1, 2, 840, 113549, 1, 7, 2};
49    public static final int[] ENVELOPED_DATA = new int[] {1, 2, 840, 113549, 1, 7, 3};
50    public static final int[] SIGNED_AND_ENVELOPED_DATA = new int[] {1, 2, 840, 113549, 1, 7, 4};
51    public static final int[] DIGESTED_DATA = new int[] {1, 2, 840, 113549, 1, 7, 5};
52    public static final int[] ENCRYPTED_DATA = new int[] {1, 2, 840, 113549, 1, 7, 6};
53
54    private int[] oid;
55    private Object content;
56    private byte[] encoding;
57
58    public ContentInfo(int[] oid, Object content) {
59        this.oid = oid;
60        this.content = content;
61    }
62
63    private ContentInfo(int[] oid, Object content, byte[] encoding) {
64        this.oid = oid;
65        this.content = content;
66        this.encoding = encoding;
67    }
68
69    public SignedData getSignedData() {
70        if (Arrays.equals(oid, SIGNED_DATA)) {
71            return (SignedData)content;
72        }
73        return null;
74    }
75
76    public Object getContent() {
77        return content;
78    }
79
80    public int[] getContentType() {
81        return oid;
82    }
83
84    public byte[] getEncoded() {
85        if (encoding == null) {
86            encoding = ASN1.encode(this);
87        }
88        // Note: this is internal object and can not be accessible from
89        // public API, so encoding is not copied. The classes which use
90        // this class should copy encoding before passing it out.
91        return encoding;
92    }
93
94    public String toString() {
95        StringBuilder res = new StringBuilder();
96        res.append("==== ContentInfo:");
97        res.append("\n== ContentType (OID): ");
98        for (int i = 0; i< oid.length; i++) {
99            res.append(oid[i]);
100            res.append(' ');
101        }
102        res.append("\n== Content: ");
103        if (content != null) {
104            res.append("\n");
105            res.append(content.toString());
106        }
107        res.append("\n== Content End");
108        res.append("\n==== ContentInfo End\n");
109        return res.toString();
110    }
111
112    public static final ASN1Sequence ASN1 =
113        new ASN1Sequence(new ASN1Type[] {
114                ASN1Oid.getInstance(),
115                new ASN1Explicit(0, ASN1Any.getInstance())
116                })  {
117        {
118            setOptional(1); // content is optional
119        }
120
121        protected void getValues(Object object, Object[] values) {
122            ContentInfo ci = (ContentInfo) object;
123            values[0] = ci.oid;
124            if (ci.content != null) {
125                if (Arrays.equals(ci.oid, DATA)) {
126                    if (ci.content != null) {
127                        values[1] =
128                            ASN1OctetString.getInstance().encode(ci.content);
129                    }
130                } else if (ci.content instanceof SignedData) {
131                    values[1] = SignedData.ASN1.encode(ci.content);
132                } else {
133                    values[1] = ci.content;
134                }
135            }
136        }
137
138        protected Object getDecodedObject(BerInputStream in) throws IOException {
139            Object[] values = (Object[]) in.content;
140            int[] oid = (int[]) values[0];
141            if (Arrays.equals(oid, DATA)) {
142                if (values[1] != null) {
143                    return new ContentInfo(oid,
144                            ASN1OctetString.getInstance().decode((byte[])values[1]),
145                            in.getEncoded());
146                }  else {
147                    return new ContentInfo((int[])values[0], null,
148                            in.getEncoded());
149                }
150            }
151            if (Arrays.equals(oid, SIGNED_DATA)) {
152                return new ContentInfo((int[])values[0],
153                        SignedData.ASN1.decode((byte[])values[1]),
154                        in.getEncoded());
155            }
156            return new ContentInfo((int[])values[0], (byte[])values[1],
157                    in.getEncoded());
158        }
159   };
160}
161