summaryrefslogtreecommitdiffstats
path: root/pki/base/util/src/netscape/security/x509/AVA.java
blob: 0614f41caa541964b19a8bad063d726ca6969073 (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
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
// --- 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 java.io.InputStream;
import java.io.OutputStream;

import netscape.security.util.DerEncoder;
import netscape.security.util.DerInputStream;
import netscape.security.util.DerOutputStream;
import netscape.security.util.DerValue;
import netscape.security.util.ObjectIdentifier;
import sun.io.ByteToCharConverter;


/**
 * X.500 Attribute-Value-Assertion (AVA):  an attribute, as identified by
 * some attribute ID, has some particular value.  Values are as a rule ASN.1
 * printable strings.  A conventional set of type IDs is recognized when
 * parsing (and generating) RFC 1779 syntax strings.
 *
 * <P>AVAs are components of X.500 relative names.  Think of them as being
 * individual fields of a database record.  The attribute ID is how you
 * identify the field, and the value is part of a particular record.
 *
 * @see X500Name
 * @see RDN
 * @see LdapDNStrConverter
 *
 * @version 1.14
 *
 * @author David Brownell
 * @author Amit Kapoor
 * @author Hemma Prafullchandra
 */
// public ... when RDN is public and X.500Names can be
// constructed using RDNs, and all three classes are cleaner
public final class AVA implements DerEncoder
{
    ObjectIdentifier	oid;
    DerValue		value;

    /** 
     * Constructs an AVA from a Ldap DN string with one AVA component 
     * using the global default LdapDNStrConverter. 
     * @see LdapDNStrConverter
     * @param avaString a Ldap DN string with one AVA component.
     */
    public AVA(String avaString)
	throws IOException
    {
	AVA ava;
	ava = LdapDNStrConverter.getDefault().parseAVA(avaString);
	oid = ava.getOid();
	value = ava.getValue();
    }

    /**
     * Like AVA(String) with a DER encoding order given for Directory Strings.
     */
    public AVA(String avaString, byte[] tags)
	throws IOException
    {
	AVA ava;
	ava = LdapDNStrConverter.getDefault().parseAVA(avaString, tags);
	oid = ava.getOid();
	value = ava.getValue();
    }

    /** 
     * Constructs an AVA from a Ldap DN string containing one AVA 
     * component using the specified LdapDNStrConverter.
     * @see LdapDNStrConverter
     * @param avaString a Ldap DN string containing one AVA.
     * @param ldapDNStrConverter a LdapDNStrConverter 
     */
    public AVA(String avaString, LdapDNStrConverter ldapDNStrConverter)
	throws IOException
    {
	AVA ava;
	ava = ldapDNStrConverter.parseAVA(avaString);
	oid = ava.getOid();
	value = ava.getValue();
    }

    /** 
     * Constructs an AVA from an OID and DerValue.
     * @param type an ObjectIdentifier
     * @param val a DerValue
     */
    public AVA(ObjectIdentifier type, DerValue val)
	throws IOException
    {
	oid = type;
	value = val;
    }

    /**
     * Constructs an AVA from an input stream of UTF8 bytes that form
     * a Ldap DN string. Then parse the Ldap DN string using the global
     * default LdapDNStrConverter.
     * <br>
     * Parses an RFC 1779 style AVA string:  CN=fee fie foe fum
     * or perhaps with quotes.  Not all defined AVA tags are supported;
     * of current note are X.400 related ones (PRMD, ADMD, etc).
     *
     * This terminates at unescaped AVA separators ("+") or RDN
     * separators (",", ";"), or DN terminators (">"), and removes
     * cosmetic whitespace at the end of values.
     * 
     * @see LdapDNStrConverter
     * @param in the input stream.
     */
    public AVA (InputStream in) throws IOException
    {
	StringBuffer	temp = new StringBuffer ();
	AVA 		a;
	byte[]		buf = new byte[in.available()];
	char[]		converted_chars;
	ByteToCharConverter bcc;

	// convert from UTF8 bytes to java string then parse it.
	in.read(buf);
	try {
	    bcc = ByteToCharConverter.getConverter("UTF8");
	}
	catch (java.io.UnsupportedEncodingException e) {
	    throw new IOException("UTF8 encoding not supported");
	}
	converted_chars = bcc.convertAll(buf);
	temp.append(converted_chars);

	a = LdapDNStrConverter.getDefault().parseAVA(temp.toString());
	oid = a.getOid();
	value = a.getValue();
    }

    /**
     * Constructs an AVA from a Der Input Stream.
     * @param in the Der Input Stream.
     */
    public AVA(DerInputStream in) throws IOException
    {
	DerValue	assertion = in.getDerValue ();

	/*
	 * Individual attribute value assertions are SEQUENCE of two values.
	 * That'd be a "struct" outside of ASN.1.
	 */
	if (assertion.tag != DerValue.tag_Sequence)
	    throw new CertParseError ("X500 AVA, not a sequence");

        ObjectIdentifier o = assertion.data.getOID();
        oid = X500NameAttrMap.getDefault().getOid(o);
        if (oid == null) {
		// NSCP #329837
		// if this OID is not recongized in our map (table),
		// it is fine. we just store it as regular OID.
                oid = o;
        }
	value = assertion.data.getDerValue ();

	if (assertion.data.available () != 0)
	    throw new CertParseError ("AVA, extra bytes = "
		+ assertion.data.available ());
    }

    // other public methods.

    /** 
     * Returns true if another AVA has the same OID and DerValue.
     * @param other the other AVA.
     * @return ture iff other AVA has same oid and value.
     */
    public boolean equals (AVA other)
    {
	return oid.equals (other.oid) && value.equals (other.value);
    }

    /** 
     * Compares the AVA with an Object, returns true if the object is 
     * an AVA and has the same OID and value.
     * @param other the other object.
     * @return true iff other object is an AVA and has same oid and value.
     */
    public boolean equals (Object other)
    {
	if (other instanceof AVA)
	    return equals ((AVA)other);
	else
	    return false;
    }

    /**
     * Encodes the AVA to a Der output stream.
     * AVAs are encoded as a SEQUENCE of two elements.
     * @param out The Der output stream.
     */
    public void encode (DerOutputStream out) throws IOException
    {
	derEncode(out);
    }
 
   /**
     * DER encode this object onto an output stream.
     * Implements the <code>DerEncoder</code> interface.
     *
     * @param out 
     * the output stream on which to write the DER encoding.
     *
     * @exception IOException on encoding error.
     */
    public void derEncode (OutputStream out) throws IOException
    {
	DerOutputStream		tmp = new DerOutputStream ();
	DerOutputStream		tmp2 = new DerOutputStream ();

	tmp.putOID (oid);
	value.encode (tmp);
	tmp2.write (DerValue.tag_Sequence, tmp);
	out.write(tmp2.toByteArray());
    }

    /**
     * Returns a Ldap DN string with one AVA component using 
     * the global default LdapDNStrConverter.
     * @return a Ldap DN string 
     * @exception IOException if an error occurs during conversion.
     * @see LdapDNStrConverter
     */
    public String toLdapDNString()
	throws IOException
    {
	LdapDNStrConverter v = LdapDNStrConverter.getDefault();
	return v.encodeAVA(this);
    }

    /**
     * Returns a Ldap DN string with one AVA component using the specified 
     * LdapDNStrConverter.
     * @return a Ldap DN string 
     * @param ldapDNStrConverter a Ldap DN String Converter 
     * @exception IOException if an error occurs during the conversion.
     * @see LdapDNStrConverter
     */
    public String toLdapDNString(LdapDNStrConverter ldapDNStrConverter)
	throws IOException
    {
	return ldapDNStrConverter.encodeAVA(this);
    }

    /**
     * Returns a Ldap DN string with the AVA component using the global
     * default LdapDNStrConverter, or null if an error occurs in conversion.
     * @return a Ldap DN string containing the AVA, or null if an 
     *		error occurs in the conversion.
     */ 
    public String toString()
    {
	String s;
	try {
	    // NOTE that a LdapDNString is returned here to match the 
	    // original source from sun. Could also return the raw value
	    // (before Ldap escaping) here.
	    s = toLdapDNString();
	}
	catch (IOException e) {
	    return null;
	}
	return s;
    }

    /** 
     * Returns the OID in the AVA.
     * @return the ObjectIdentifier in this AVA.
     */
    public ObjectIdentifier getOid()
    {
	return oid;
    }

    /** 
     * Returns the value in this AVA as a DerValue
     * @return attribute value in this AVA.
     */
    public DerValue getValue()
    {
	return value;
    }

}