OSDN Git Service

Fix cert code to use the String form for TELETEX-encoded certs; see bug 2102191.
[android-x86/dalvik.git] / libcore / security / src / main / java / org / apache / harmony / security / x501 / AttributeTypeAndValue.java
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 Alexander V. Esin, Stepan M. Mishura
20 * @version $Revision$
21 */
22
23 package org.apache.harmony.security.x501;
24
25 import java.io.IOException;
26 import java.util.Arrays;
27 import java.util.HashMap;
28 import java.util.Iterator;
29
30 import javax.security.auth.x500.X500Principal;
31
32 import org.apache.harmony.security.asn1.ASN1Constants;
33 import org.apache.harmony.security.asn1.ASN1Oid;
34 import org.apache.harmony.security.asn1.ASN1Sequence;
35 import org.apache.harmony.security.asn1.ASN1StringType;
36 import org.apache.harmony.security.asn1.ASN1Type;
37 import org.apache.harmony.security.asn1.BerInputStream;
38 import org.apache.harmony.security.asn1.BerOutputStream;
39 import org.apache.harmony.security.internal.nls.Messages;
40 import org.apache.harmony.security.utils.ObjectIdentifier;
41
42
43 /**
44  * X.501 AttributeTypeAndValue
45  */
46 public class AttributeTypeAndValue {
47
48     // Country code attribute (name from RFC 1779)
49     private static final ObjectIdentifier C;
50
51     // Common name attribute (name from RFC 1779)
52     private static final ObjectIdentifier CN;
53
54     // Domain component attribute (name from RFC 2253)
55     private static final ObjectIdentifier DC;
56
57     // DN qualifier attribute (name from API spec)
58     private static final ObjectIdentifier DNQ;
59
60     private static final ObjectIdentifier DNQUALIFIER;
61
62     // Email Address attribute (name from API spec)
63     private static final ObjectIdentifier EMAILADDRESS;
64
65     // Generation attribute (qualifies an individual's name)
66     // (name from API spec)
67     private static final ObjectIdentifier GENERATION;
68
69     // Given name attribute (name from API spec)
70     private static final ObjectIdentifier GIVENNAME;
71
72     // Initials attribute (initials of an individual's name)
73     // (name from API spec)
74     private static final ObjectIdentifier INITIALS;
75
76     // Name of a locality attribute (name from RFC 1779)
77     private static final ObjectIdentifier L;
78
79     // Organization name attribute (name from RFC 1779)
80     private static final ObjectIdentifier O;
81
82     // Organizational unit name attribute (name from RFC 1779)
83     private static final ObjectIdentifier OU;
84
85     // Serial number attribute (serial number of a device)
86     // (name from API spec)
87     private static final ObjectIdentifier SERIALNUMBER;
88
89     // Attribute for the full name of a state or province
90     // (name from RFC 1779)
91     private static final ObjectIdentifier ST;
92
93     // Street attribute (name from RFC 1779)
94     private static final ObjectIdentifier STREET;
95
96     // Surname attribute (comes from an individual's parent name) 
97     // (name from API spec)
98     private static final ObjectIdentifier SURNAME;
99
100     // Title attribute (object in an organization)(name from API spec)
101     private static final ObjectIdentifier T;
102
103     // User identifier attribute (name from RFC 2253)
104     private static final ObjectIdentifier UID;
105
106     //
107     // OID's pool
108     //
109
110     // pool's capacity
111     private static final int CAPACITY;
112
113     // pool's size
114     private static final int SIZE;
115
116     // pool: contains all recognizable attribute type keywords
117     private static final ObjectIdentifier[][] KNOWN_OIDS;
118
119     // known keywords attribute
120     private static final HashMap KNOWN_NAMES = new HashMap(30);
121
122     // known attribute types for RFC1779 (see Table 1)
123     private static final HashMap RFC1779_NAMES = new HashMap(10);
124
125     // known attribute types for RFC2253
126     // (see 2.3.  Converting AttributeTypeAndValue)
127     private static final HashMap RFC2253_NAMES = new HashMap(10);
128
129     // known attribute types for RFC2459 (see API spec.)
130     private static final HashMap RFC2459_NAMES = new HashMap(10);
131
132     static {
133
134         // pool initialization
135         CAPACITY = 10;
136         SIZE = 10;
137         KNOWN_OIDS = new ObjectIdentifier[SIZE][CAPACITY];
138
139         // init known attribute type keywords
140         C = new ObjectIdentifier(new int[] { 2, 5, 4, 6 }, "C", RFC1779_NAMES); //$NON-NLS-1$
141         CN = new ObjectIdentifier(new int[] { 2, 5, 4, 3 }, "CN", RFC1779_NAMES); //$NON-NLS-1$
142
143         DC = new ObjectIdentifier(
144                 new int[] { 0, 9, 2342, 19200300, 100, 1, 25 }, "DC", //$NON-NLS-1$
145                 RFC2253_NAMES);
146         // DN qualifier aliases
147         DNQ = new ObjectIdentifier(new int[] { 2, 5, 4, 46 }, "DNQ", //$NON-NLS-1$
148                 RFC2459_NAMES);
149         DNQUALIFIER = new ObjectIdentifier(new int[] { 2, 5, 4, 46 },
150                 "DNQUALIFIER", RFC2459_NAMES); //$NON-NLS-1$
151
152         EMAILADDRESS = new ObjectIdentifier(new int[] { 1, 2, 840, 113549, 1,
153                 9, 1 }, "EMAILADDRESS", RFC2459_NAMES); //$NON-NLS-1$
154
155         GENERATION = new ObjectIdentifier(new int[] { 2, 5, 4, 44 },
156                 "GENERATION", RFC2459_NAMES); //$NON-NLS-1$
157         GIVENNAME = new ObjectIdentifier(new int[] { 2, 5, 4, 42 },
158                 "GIVENNAME", RFC2459_NAMES); //$NON-NLS-1$
159
160         INITIALS = new ObjectIdentifier(new int[] { 2, 5, 4, 43 }, "INITIALS", //$NON-NLS-1$
161                 RFC2459_NAMES);
162
163         L = new ObjectIdentifier(new int[] { 2, 5, 4, 7 }, "L", RFC1779_NAMES); //$NON-NLS-1$
164
165         O = new ObjectIdentifier(new int[] { 2, 5, 4, 10 }, "O", RFC1779_NAMES); //$NON-NLS-1$
166         OU = new ObjectIdentifier(new int[] { 2, 5, 4, 11 }, "OU", //$NON-NLS-1$
167                 RFC1779_NAMES);
168
169         SERIALNUMBER = new ObjectIdentifier(new int[] { 2, 5, 4, 5 },
170                 "SERIALNUMBER", RFC2459_NAMES); //$NON-NLS-1$
171         ST = new ObjectIdentifier(new int[] { 2, 5, 4, 8 }, "ST", RFC1779_NAMES); //$NON-NLS-1$
172         STREET = new ObjectIdentifier(new int[] { 2, 5, 4, 9 }, "STREET", //$NON-NLS-1$
173                 RFC1779_NAMES);
174         SURNAME = new ObjectIdentifier(new int[] { 2, 5, 4, 4 }, "SURNAME", //$NON-NLS-1$
175                 RFC2459_NAMES);
176
177         T = new ObjectIdentifier(new int[] { 2, 5, 4, 12 }, "T", RFC2459_NAMES); //$NON-NLS-1$
178
179         UID = new ObjectIdentifier(
180                 new int[] { 0, 9, 2342, 19200300, 100, 1, 1 }, "UID", //$NON-NLS-1$
181                 RFC2253_NAMES);
182
183         //
184         // RFC1779
185         //
186         RFC1779_NAMES.put(CN.getName(), CN);
187         RFC1779_NAMES.put(L.getName(), L);
188         RFC1779_NAMES.put(ST.getName(), ST);
189         RFC1779_NAMES.put(O.getName(), O);
190         RFC1779_NAMES.put(OU.getName(), OU);
191         RFC1779_NAMES.put(C.getName(), C);
192         RFC1779_NAMES.put(STREET.getName(), STREET);
193
194         //
195         // RFC2253: includes all from RFC1779
196         //
197         RFC2253_NAMES.putAll(RFC1779_NAMES);
198
199         RFC2253_NAMES.put(DC.getName(), DC);
200         RFC2253_NAMES.put(UID.getName(), UID);
201
202         //
203         // RFC2459
204         //
205         RFC2459_NAMES.put(DNQ.getName(), DNQ);
206         RFC2459_NAMES.put(DNQUALIFIER.getName(), DNQUALIFIER);
207         RFC2459_NAMES.put(EMAILADDRESS.getName(), EMAILADDRESS);
208         RFC2459_NAMES.put(GENERATION.getName(), GENERATION);
209         RFC2459_NAMES.put(GIVENNAME.getName(), GIVENNAME);
210         RFC2459_NAMES.put(INITIALS.getName(), INITIALS);
211         RFC2459_NAMES.put(SERIALNUMBER.getName(), SERIALNUMBER);
212         RFC2459_NAMES.put(SURNAME.getName(), SURNAME);
213         RFC2459_NAMES.put(T.getName(), T);
214
215         //
216         // Init KNOWN_OIDS pool
217         //
218
219         // add from RFC2253 (includes RFC1779) 
220         Iterator it = RFC2253_NAMES.values().iterator();
221         while (it.hasNext()) {
222             addOID((ObjectIdentifier) it.next());
223         }
224
225         // add attributes from RFC2459
226         it = RFC2459_NAMES.values().iterator();
227         while (it.hasNext()) {
228             Object o = it.next();
229
230             //don't add DNQUALIFIER because it has the same oid as DNQ
231             if (!(o == DNQUALIFIER)) {
232                 addOID((ObjectIdentifier) o);
233             }
234         }
235
236         //
237         // Init KNOWN_NAMES pool
238         //
239
240         KNOWN_NAMES.putAll(RFC2253_NAMES); // RFC2253 includes RFC1779
241         KNOWN_NAMES.putAll(RFC2459_NAMES);
242     }
243
244     //Attribute type
245     private final ObjectIdentifier oid;
246
247     //Attribute value
248     private AttributeValue value;
249
250     // for decoder only
251     private AttributeTypeAndValue(int[] oid, AttributeValue value)
252             throws IOException {
253
254         ObjectIdentifier thisOid = getOID(oid);
255         if (thisOid == null) {
256             thisOid = new ObjectIdentifier(oid);
257         }
258         this.oid = thisOid;
259         this.value = value;
260     }
261
262     /**
263      * Creates AttributeTypeAndValue with OID and AttributeValue. Parses OID
264      * string representation
265      * 
266      * @param sOid
267      *            string representation of OID
268      * @param value
269      *            attribute value
270      * @throws IOException
271      *             if OID can not be created from its string representation
272      */
273     public AttributeTypeAndValue(String sOid, AttributeValue value)
274             throws IOException {
275         if (sOid.charAt(0) >= '0' && sOid.charAt(0) <= '9') {
276
277             int[] array = org.apache.harmony.security.asn1.ObjectIdentifier
278                     .toIntArray(sOid);
279
280             ObjectIdentifier thisOid = getOID(array);
281             if (thisOid == null) {
282                 thisOid = new ObjectIdentifier(array);
283             }
284             this.oid = thisOid;
285
286         } else {
287             this.oid = (ObjectIdentifier) KNOWN_NAMES.get(sOid.toUpperCase());
288             if (this.oid == null) {
289                 throw new IOException(Messages.getString("security.178", sOid)); //$NON-NLS-1$
290             }
291         }
292         this.value = value;
293     }
294
295     /**
296      * Appends AttributeTypeAndValue string representation
297      * 
298      * @param attrFormat - format of DN
299      * @param buf - string buffer to be used
300      */
301     public void appendName(String attrFormat, StringBuffer buf) {
302
303         boolean hexFormat = false;
304         if (attrFormat == X500Principal.RFC1779) {
305             if (RFC1779_NAMES == oid.getGroup()) {
306                 buf.append(oid.getName());
307             } else {
308                 buf.append(oid.toOIDString());
309             }
310
311             buf.append('=');
312             if (value.escapedString == value.getHexString()) {
313                 //FIXME all chars in upper case
314                 buf.append(value.getHexString().toUpperCase());
315             } else if (value.escapedString.length() != value.rawString.length()) {
316                 // was escaped
317                 value.appendQEString(buf);
318             } else {
319                 buf.append(value.escapedString);
320             }
321         } else {
322             Object group = oid.getGroup();
323             // RFC2253 includes names from RFC1779
324             if (RFC1779_NAMES == group || RFC2253_NAMES == group) {
325                 buf.append(oid.getName());
326
327                 if (attrFormat == X500Principal.CANONICAL) {
328                     // only PrintableString and UTF8String in string format
329                     // all others are output in hex format
330                     // BEGIN android-changed
331                     // no hex for teletex; see bug 2102191
332                     int tag = value.getTag();
333                     if (!ASN1StringType.UTF8STRING.checkTag(tag)
334                             && !ASN1StringType.PRINTABLESTRING.checkTag(tag)
335                             && !ASN1StringType.TELETEXSTRING.checkTag(tag)) {
336                         hexFormat = true;
337                     }
338                     // END android-changed
339                 }
340
341             } else {
342                 buf.append(oid.toString());
343                 hexFormat = true;
344             }
345
346             buf.append('=');
347
348             if (hexFormat) {
349                 buf.append(value.getHexString());
350             } else {
351                 if (attrFormat == X500Principal.CANONICAL) {
352                     buf.append(value.makeCanonical());
353                 } else {
354                     buf.append(value.escapedString);
355                 }
356             }
357         }
358     }
359
360     /**
361      * Gets type of the AttributeTypeAndValue
362      * 
363      * @return ObjectIdentifier
364      */
365     public ObjectIdentifier getType() {
366         return oid;
367     }
368
369     /**
370      * According to RFC 3280 (http://www.ietf.org/rfc/rfc3280.txt) 
371      * X.501 AttributeTypeAndValue structure is defined as follows:
372      *  
373      *   AttributeTypeAndValue ::= SEQUENCE {
374      *      type     AttributeType,
375      *      value    AttributeValue }
376      *   
377      *    AttributeType ::= OBJECT IDENTIFIER
378      *  
379      *    AttributeValue ::= ANY DEFINED BY AttributeType
380      *    ...
381      *    DirectoryString ::= CHOICE {
382      *          teletexString           TeletexString (SIZE (1..MAX)),
383      *          printableString         PrintableString (SIZE (1..MAX)),
384      *          universalString         UniversalString (SIZE (1..MAX)),
385      *          utf8String              UTF8String (SIZE (1.. MAX)),
386      *          bmpString               BMPString (SIZE (1..MAX)) }
387      *  
388      */
389
390     public static ASN1Type AttributeValue = new ASN1Type(
391             ASN1Constants.TAG_PRINTABLESTRING) {
392
393         public boolean checkTag(int tag) {
394             return true;
395         }
396
397         public Object decode(BerInputStream in) throws IOException {
398
399             // FIXME what about constr???
400             String str = null;
401             if (DirectoryString.ASN1.checkTag(in.tag)) {
402                 // has string representation
403                 str = (String) DirectoryString.ASN1.decode(in);
404             } else {
405                 // gets octets only
406                 in.readContent();
407             }
408
409             byte[] bytesEncoded = new byte[in.getOffset() - in.getTagOffset()];
410             System.arraycopy(in.getBuffer(), in.getTagOffset(), bytesEncoded,
411                     0, bytesEncoded.length);
412
413             return new AttributeValue(str, bytesEncoded, in.tag);
414         }
415
416         public Object getDecodedObject(BerInputStream in) throws IOException {
417             // stub to avoid wrong decoder usage
418             throw new RuntimeException(Messages.getString("security.179")); //$NON-NLS-1$
419         }
420
421         //
422         // Encode
423         //
424         public void encodeASN(BerOutputStream out) {
425
426             AttributeValue av = (AttributeValue) out.content;
427
428             if (av.encoded != null) {
429                 out.content = av.encoded;
430                 out.encodeANY();
431             } else {
432                 out.encodeTag(av.getTag());
433                 out.content = av.bytes;
434                 out.encodeString();
435             }
436         }
437
438         public void setEncodingContent(BerOutputStream out) {
439             
440             AttributeValue av = (AttributeValue) out.content;
441
442             if (av.encoded != null) {
443                 out.length = av.encoded.length;
444             } else {
445
446                 if (av.getTag() == ASN1Constants.TAG_UTF8STRING) {
447
448                     out.content = av.rawString;
449
450                     ASN1StringType.UTF8STRING.setEncodingContent(out);
451
452                     av.bytes = (byte[]) out.content;
453                     out.content = av;
454                 } else {
455                     av.bytes = av.rawString.getBytes();
456                     out.length = av.bytes.length;
457                 }
458             }
459         }
460
461         public void encodeContent(BerOutputStream out) {
462             // stub to avoid wrong encoder usage
463             throw new RuntimeException(Messages.getString("security.17A")); //$NON-NLS-1$
464         }
465
466         public int getEncodedLength(BerOutputStream out) { //FIXME name
467
468             AttributeValue av = (AttributeValue) out.content;
469
470             if (av.encoded != null) {
471                 return out.length;
472             } else {
473                 return super.getEncodedLength(out);
474             }
475         }
476     };
477
478     public static final ASN1Sequence ASN1 = new ASN1Sequence(new ASN1Type[] {
479             ASN1Oid.getInstance(), AttributeValue }) {
480
481         protected Object getDecodedObject(BerInputStream in) throws IOException {
482             Object[] values = (Object[]) in.content;
483             return new AttributeTypeAndValue((int[]) values[0],
484                     (AttributeValue) values[1]);
485         }
486
487         protected void getValues(Object object, Object[] values) {
488             AttributeTypeAndValue atav = (AttributeTypeAndValue) object;
489
490             values[0] = atav.oid.getOid();
491             values[1] = atav.value;
492         }
493     };
494
495     // returns known OID or null
496     private static ObjectIdentifier getOID(int[] oid) {
497
498         int index = hashIntArray(oid) % CAPACITY;
499
500         // look for OID in the pool 
501         ObjectIdentifier[] list = KNOWN_OIDS[index];
502         for (int i = 0; list[i] != null; i++) {
503             if (Arrays.equals(oid, list[i].getOid())) {
504                 return list[i];
505             }
506         }
507         return null;
508     }
509
510     // adds known OID to pool
511     // for static AttributeTypeAndValue initialization only
512     private static void addOID(ObjectIdentifier oid) {
513
514         int[] newOid = oid.getOid();
515         int index = hashIntArray(newOid) % CAPACITY;
516
517         // look for OID in the pool 
518         ObjectIdentifier[] list = KNOWN_OIDS[index];
519         int i = 0;
520         for (; list[i] != null; i++) {
521
522             // check wrong static initialization: no duplicate OIDs
523             if (Arrays.equals(newOid, list[i].getOid())) {
524                 throw new Error(Messages.getString("security.17B", //$NON-NLS-1$
525                                 oid.getName(), list[i].getName()));
526             }
527         }
528
529         // check : to avoid NPE
530         if (i == (CAPACITY - 1)) {
531             throw new Error(Messages.getString("security.17C")); //$NON-NLS-1$
532         }
533         list[i] = oid;
534     }
535
536     // returns hash for array of integers
537     private static int hashIntArray(int[] oid) {
538         int intHash = 0;
539         for (int i = 0; i < oid.length && i < 4; i++) {
540             intHash += oid[i] << (8 * i); //TODO what about to find better one?
541         }
542         return intHash & 0x7FFFFFFF; // only positive
543     }
544 }