summaryrefslogtreecommitdiffstats
path: root/pki/base/util/src/netscape/security/x509/GeneralName.java
blob: 84088147e0ad2c14f89c1bc42606bd320b9b174d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
// --- BEGIN COPYRIGHT BLOCK ---
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 2 of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
// (C) 2007 Red Hat, Inc.
// All rights reserved.
// --- END COPYRIGHT BLOCK ---
package netscape.security.x509;

import java.io.IOException;

import netscape.security.util.DerOutputStream;
import netscape.security.util.DerValue;

/**
 * This class implements the ASN.1 GeneralName object class.
 * <p>
 * The ASN.1 syntax for this is:
 * <pre>
 * GeneralName ::= CHOICE {
 *    otherName                       [0]     OtherName,
 *    rfc822Name                      [1]     IA5String,
 *    dNSName                         [2]     IA5String,
 *    x400Address                     [3]     ORAddress,
 *    directoryName                   [4]     Name,
 *    ediPartyName                    [5]     EDIPartyName,
 *    uniformResourceIdentifier       [6]     IA5String,
 *    iPAddress                       [7]     OCTET STRING,
 *    registeredID                    [8]     OBJECT IDENTIFIER
 * }
 * </pre>
 * @author Amit Kapoor
 * @author Hemma Prafullchandra
 * @version 1.7
 */
public class GeneralName implements GeneralNameInterface {

    // Private data members
    private GeneralNameInterface name = null;

    /**
     * Default constructor for the class.
     *
     * @param name the selected CHOICE from the list.
     */
    public GeneralName(GeneralNameInterface name) {
        this.name = name;
    }

    /**
     * Create the object from its DER encoded value.
     *
     * @param encName the DER encoded GeneralName.
     */
    public GeneralName(DerValue encName) throws IOException {
        short tag = (byte)(encName.tag & 0x1f);

        // NB. this is always encoded with the IMPLICIT tag 
        // The checks only make sense if we assume implicit tagging, 
        // with explicit tagging the form is always constructed. 
        switch (tag) {
        case GeneralNameInterface.NAME_RFC822:
            if (encName.isContextSpecific() && !encName.isConstructed()) {
                encName.resetTag(DerValue.tag_IA5String);
	        name = new RFC822Name(encName);
            } else
	        throw new IOException("Invalid encoding of RFC822 name");
	    break;

        case GeneralNameInterface.NAME_DNS:
            if (encName.isContextSpecific() && !encName.isConstructed()) {
                encName.resetTag(DerValue.tag_IA5String);
	        name = new DNSName(encName);
            } else
	        throw new IOException("Invalid encoding of DNS name");
	    break;

        case GeneralNameInterface.NAME_URI:
            if (encName.isContextSpecific() && !encName.isConstructed()) {
                encName.resetTag(DerValue.tag_IA5String);
	        name = new URIName(encName);
            } else
	        throw new IOException("Invalid encoding of URI");
	    break;

        case GeneralNameInterface.NAME_IP:
            if (encName.isContextSpecific() && !encName.isConstructed()) {
                encName.resetTag(DerValue.tag_OctetString);
	        name = new IPAddressName(encName);
            } else
	        throw new IOException("Invalid encoding of IP address");
	    break;

          case GeneralNameInterface.NAME_ANY:
              if (encName.isContextSpecific() && encName.isConstructed()) {
                  encName.resetTag(DerValue.tag_OctetString);
                name = new OtherName(encName);
              } else
                throw new IOException("Invalid encoding of other name");
            break;

        case GeneralNameInterface.NAME_OID:
            if (encName.isContextSpecific() && !encName.isConstructed()) {
                encName.resetTag(DerValue.tag_ObjectId);
	        name = new OIDName(encName);
            } else
	        throw new IOException("Invalid encoding of OID name");
	    break;

        case GeneralNameInterface.NAME_DIRECTORY:
            if (encName.isContextSpecific() && encName.isConstructed()) {
                // Unlike the other cases, DirectoryName is EXPLICITly
                // tagged, because the X.500 Name type is a CHOICE.
                // Therefore, the sequence is actually nested in the
                // content of this value.  We'll pretend it's an octet
                // string so we can get at the content bytes.
                encName.resetTag(DerValue.tag_OctetString);
                byte[] content = encName.getOctetString();
                name = new X500Name( content );
            } else
	        throw new IOException("Invalid encoding of Directory name");
	    break;

        case GeneralNameInterface.NAME_EDI:
            if (encName.isContextSpecific() && encName.isConstructed()) {
                encName.resetTag(DerValue.tag_Sequence);
                name = new EDIPartyName(encName);
            } else
	        throw new IOException("Invalid encoding of EDI name");
	    break;

        default:
	    throw new IOException("Unrecognized GeneralName tag, ("
                                  + tag +")");
        }      
    }

    /**
     * Return the type of the general name.
     */
    public int getType() {
        return (name.getType());
    }

    /**
     * Return the name as user readable string
     */
    public String toString() {
        return (name.toString());
    }

   /**
    * Encode the name to the specified DerOutputStream.
    *
    * @param out the DerOutputStream to encode the the GeneralName to.
    * @exception IOException on encoding errors.
    */
   public void encode(DerOutputStream out) throws IOException {
       DerOutputStream tmp = new DerOutputStream();
       name.encode(tmp);
       int nameType = name.getType();
       boolean constructedForm;

       if (nameType == GeneralNameInterface.NAME_ANY ||
           nameType == GeneralNameInterface.NAME_X400 ||
           nameType == GeneralNameInterface.NAME_DIRECTORY ||
           nameType == GeneralNameInterface.NAME_EDI) {
                constructedForm = true;
       } else {
                constructedForm = false;
       }

       if( nameType == GeneralNameInterface.NAME_DIRECTORY ) {
           // EXPLICIT tag, because Name is a CHOICE type
           out.write(DerValue.createTag(DerValue.TAG_CONTEXT,
                             constructedForm, (byte)nameType), tmp);
       } else {
           // IMPLICIT tag, the default
           out.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT,
                             constructedForm, (byte)nameType), tmp);
       }
   }
}