Roll android_tools support library to 25.1.0
[android_tools.git] / sdk / sources / android-23 / org / apache / harmony / security / x501 / AttributeTypeAndValue.java
blob171d9c27107abdaa91832e8e462c28deb1baaf8c
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 /**
19 * @author Alexander V. Esin, Stepan M. Mishura
20 * @version $Revision$
23 package org.apache.harmony.security.x501;
25 import java.io.IOException;
26 import java.nio.charset.StandardCharsets;
27 import java.util.Arrays;
28 import java.util.HashMap;
29 import java.util.Locale;
30 import javax.security.auth.x500.X500Principal;
31 import org.apache.harmony.security.asn1.ASN1Constants;
32 import org.apache.harmony.security.asn1.ASN1Oid;
33 import org.apache.harmony.security.asn1.ASN1Sequence;
34 import org.apache.harmony.security.asn1.ASN1StringType;
35 import org.apache.harmony.security.asn1.ASN1Type;
36 import org.apache.harmony.security.asn1.BerInputStream;
37 import org.apache.harmony.security.asn1.BerOutputStream;
38 import org.apache.harmony.security.utils.ObjectIdentifier;
41 /**
42 * X.501 AttributeTypeAndValue
44 public final class AttributeTypeAndValue {
46 /** known attribute types for RFC1779 (see Table 1) */
47 private static final HashMap<String, ObjectIdentifier> RFC1779_NAMES
48 = new HashMap<String, ObjectIdentifier>(10);
50 /** known keywords attribute */
51 private static final HashMap<String, ObjectIdentifier> KNOWN_NAMES
52 = new HashMap<String, ObjectIdentifier>(30);
54 /** known attribute types for RFC2253 (see 2.3. Converting AttributeTypeAndValue) */
55 private static final HashMap<String, ObjectIdentifier> RFC2253_NAMES
56 = new HashMap<String, ObjectIdentifier>(10);
58 /** known attribute types for RFC2459 (see API spec.) */
59 private static final HashMap<String, ObjectIdentifier> RFC2459_NAMES
60 = new HashMap<String, ObjectIdentifier>(10);
62 /** Country code attribute (name from RFC 1779) */
63 private static final ObjectIdentifier C
64 = new ObjectIdentifier(new int[] { 2, 5, 4, 6 }, "C", RFC1779_NAMES);
66 /** Common name attribute (name from RFC 1779) */
67 private static final ObjectIdentifier CN
68 = new ObjectIdentifier(new int[] { 2, 5, 4, 3 }, "CN", RFC1779_NAMES);
70 /** Domain component attribute (name from RFC 2253) */
71 public static final ObjectIdentifier DC = new ObjectIdentifier(
72 new int[] { 0, 9, 2342, 19200300, 100, 1, 25 }, "DC", RFC2253_NAMES);
74 /** DN qualifier attribute (name from API spec) */
75 private static final ObjectIdentifier DNQ
76 = new ObjectIdentifier(new int[] { 2, 5, 4, 46 }, "DNQ", RFC2459_NAMES);
78 private static final ObjectIdentifier DNQUALIFIER
79 = new ObjectIdentifier(new int[] { 2, 5, 4, 46 }, "DNQUALIFIER", RFC2459_NAMES);
81 /** Email Address attribute (name from API spec) */
82 public static final ObjectIdentifier EMAILADDRESS = new ObjectIdentifier(
83 new int[] { 1, 2, 840, 113549, 1, 9, 1}, "EMAILADDRESS", RFC2459_NAMES);
85 /** Generation attribute (qualifies an individual's name) (name from API spec) */
86 private static final ObjectIdentifier GENERATION
87 = new ObjectIdentifier(new int[] { 2, 5, 4, 44 }, "GENERATION", RFC2459_NAMES);
89 /** Given name attribute (name from API spec) */
90 private static final ObjectIdentifier GIVENNAME
91 = new ObjectIdentifier(new int[] { 2, 5, 4, 42 }, "GIVENNAME", RFC2459_NAMES);
93 /** Initials attribute (initials of an individual's name) (name from API spec) */
94 private static final ObjectIdentifier INITIALS
95 = new ObjectIdentifier(new int[] { 2, 5, 4, 43 }, "INITIALS", RFC2459_NAMES);
97 /** Name of a locality attribute (name from RFC 1779) */
98 private static final ObjectIdentifier L
99 = new ObjectIdentifier(new int[] { 2, 5, 4, 7 }, "L", RFC1779_NAMES);
101 /** Organization name attribute (name from RFC 1779) */
102 private static final ObjectIdentifier O
103 = new ObjectIdentifier(new int[] { 2, 5, 4, 10 }, "O", RFC1779_NAMES);
105 /** Organizational unit name attribute (name from RFC 1779) */
106 private static final ObjectIdentifier OU
107 = new ObjectIdentifier(new int[] { 2, 5, 4, 11 }, "OU", RFC1779_NAMES);
109 /** Serial number attribute (serial number of a device) (name from API spec) */
110 private static final ObjectIdentifier SERIALNUMBER
111 = new ObjectIdentifier(new int[] { 2, 5, 4, 5 }, "SERIALNUMBER", RFC2459_NAMES);
113 /** Attribute for the full name of a state or province (name from RFC 1779) */
114 private static final ObjectIdentifier ST
115 = new ObjectIdentifier(new int[] { 2, 5, 4, 8 }, "ST", RFC1779_NAMES);
117 /** Street attribute (name from RFC 1779) */
118 private static final ObjectIdentifier STREET
119 = new ObjectIdentifier(new int[] { 2, 5, 4, 9 }, "STREET", RFC1779_NAMES);
121 /** Surname attribute (comes from an individual's parent name) (name from API spec) */
122 private static final ObjectIdentifier SURNAME
123 = new ObjectIdentifier(new int[] { 2, 5, 4, 4 }, "SURNAME", RFC2459_NAMES);
125 /** Title attribute (object in an organization)(name from API spec) */
126 private static final ObjectIdentifier T
127 = new ObjectIdentifier(new int[] { 2, 5, 4, 12 }, "T", RFC2459_NAMES);
129 /** User identifier attribute (name from RFC 2253) */
130 private static final ObjectIdentifier UID = new ObjectIdentifier(
131 new int[]{ 0, 9, 2342, 19200300, 100, 1, 1 }, "UID", RFC2253_NAMES);
133 /** pool's capacity */
134 private static final int CAPACITY = 10;
136 /** pool's size */
137 private static final int SIZE = 10;
139 /** pool: contains all recognizable attribute type keywords */
140 private static final ObjectIdentifier[][] KNOWN_OIDS = new ObjectIdentifier[SIZE][CAPACITY];
142 static {
143 RFC1779_NAMES.put(CN.getName(), CN);
144 RFC1779_NAMES.put(L.getName(), L);
145 RFC1779_NAMES.put(ST.getName(), ST);
146 RFC1779_NAMES.put(O.getName(), O);
147 RFC1779_NAMES.put(OU.getName(), OU);
148 RFC1779_NAMES.put(C.getName(), C);
149 RFC1779_NAMES.put(STREET.getName(), STREET);
151 RFC2253_NAMES.putAll(RFC1779_NAMES);
152 RFC2253_NAMES.put(DC.getName(), DC);
153 RFC2253_NAMES.put(UID.getName(), UID);
155 RFC2459_NAMES.put(DNQ.getName(), DNQ);
156 RFC2459_NAMES.put(DNQUALIFIER.getName(), DNQUALIFIER);
157 RFC2459_NAMES.put(EMAILADDRESS.getName(), EMAILADDRESS);
158 RFC2459_NAMES.put(GENERATION.getName(), GENERATION);
159 RFC2459_NAMES.put(GIVENNAME.getName(), GIVENNAME);
160 RFC2459_NAMES.put(INITIALS.getName(), INITIALS);
161 RFC2459_NAMES.put(SERIALNUMBER.getName(), SERIALNUMBER);
162 RFC2459_NAMES.put(SURNAME.getName(), SURNAME);
163 RFC2459_NAMES.put(T.getName(), T);
165 // add from RFC2253 (includes RFC1779)
166 for (ObjectIdentifier objectIdentifier : RFC2253_NAMES.values()) {
167 addOID(objectIdentifier);
170 // add attributes from RFC2459
171 for (ObjectIdentifier o : RFC2459_NAMES.values()) {
172 //don't add DNQUALIFIER because it has the same oid as DNQ
173 if (!(o == DNQUALIFIER)) {
174 addOID(o);
178 KNOWN_NAMES.putAll(RFC2253_NAMES); // RFC2253 includes RFC1779
179 KNOWN_NAMES.putAll(RFC2459_NAMES);
183 * Parses OID string representation.
185 * @param sOid
186 * string representation of OID
188 * @throws IOException
189 * if OID can not be created from its string representation
191 public static ObjectIdentifier getObjectIdentifier(String sOid) throws IOException {
192 if (sOid.charAt(0) >= '0' && sOid.charAt(0) <= '9') {
193 int[] array = org.apache.harmony.security.asn1.ObjectIdentifier.toIntArray(sOid);
194 ObjectIdentifier thisOid = getOID(array);
195 if (thisOid == null) {
196 thisOid = new ObjectIdentifier(array);
198 return thisOid;
201 ObjectIdentifier thisOid = KNOWN_NAMES.get(sOid.toUpperCase(Locale.US));
202 if (thisOid == null) {
203 throw new IOException("Unrecognizable attribute name: " + sOid);
205 return thisOid;
208 /** Attribute type */
209 private final ObjectIdentifier oid;
211 /** Attribute value */
212 private final AttributeValue value;
214 // for decoder only
215 private AttributeTypeAndValue(int[] oid, AttributeValue value) throws IOException {
216 ObjectIdentifier thisOid = getOID(oid);
217 if (thisOid == null) {
218 thisOid = new ObjectIdentifier(oid);
220 this.oid = thisOid;
221 this.value = value;
225 * Creates AttributeTypeAndValue with OID and AttributeValue.
227 * @param oid
228 * object identifier
229 * @param value
230 * attribute value
232 public AttributeTypeAndValue(ObjectIdentifier oid, AttributeValue value) throws IOException {
233 this.oid = oid;
234 this.value = value;
238 * Appends AttributeTypeAndValue string representation
240 * @param attrFormat - format of DN
242 public void appendName(String attrFormat, StringBuilder sb) {
243 boolean hexFormat = false;
244 if (X500Principal.RFC1779.equals(attrFormat)) {
245 if (RFC1779_NAMES == oid.getGroup()) {
246 sb.append(oid.getName());
247 } else {
248 sb.append(oid.toOIDString());
251 sb.append('=');
252 if (value.escapedString == value.getHexString()) {
253 sb.append(value.getHexString().toUpperCase(Locale.US));
254 } else if (value.escapedString.length() != value.rawString.length()) {
255 // was escaped
256 value.appendQEString(sb);
257 } else {
258 sb.append(value.escapedString);
260 } else {
261 Object group = oid.getGroup();
262 // RFC2253 includes names from RFC1779
263 if (RFC1779_NAMES == group || RFC2253_NAMES == group) {
264 sb.append(oid.getName());
266 if (X500Principal.CANONICAL.equals(attrFormat)) {
267 // only PrintableString and UTF8String in string format
268 // all others are output in hex format
269 // no hex for teletex; see http://b/2102191
270 int tag = value.getTag();
271 if (!ASN1StringType.UTF8STRING.checkTag(tag)
272 && !ASN1StringType.PRINTABLESTRING.checkTag(tag)
273 && !ASN1StringType.TELETEXSTRING.checkTag(tag)) {
274 hexFormat = true;
278 } else {
279 sb.append(oid.toString());
280 hexFormat = true;
283 sb.append('=');
285 if (hexFormat) {
286 sb.append(value.getHexString());
287 } else {
288 if (X500Principal.CANONICAL.equals(attrFormat)) {
289 sb.append(value.makeCanonical());
290 } else if (X500Principal.RFC2253.equals(attrFormat)) {
291 sb.append(value.getRFC2253String());
292 } else {
293 sb.append(value.escapedString);
300 * Gets type of the AttributeTypeAndValue
302 public ObjectIdentifier getType() {
303 return oid;
306 public AttributeValue getValue() {
307 return value;
311 * According to RFC 3280 (http://www.ietf.org/rfc/rfc3280.txt)
312 * X.501 AttributeTypeAndValue structure is defined as follows:
314 * AttributeTypeAndValue ::= SEQUENCE {
315 * type AttributeType,
316 * value AttributeValue }
318 * AttributeType ::= OBJECT IDENTIFIER
320 * AttributeValue ::= ANY DEFINED BY AttributeType
321 * ...
322 * DirectoryString ::= CHOICE {
323 * teletexString TeletexString (SIZE (1..MAX)),
324 * printableString PrintableString (SIZE (1..MAX)),
325 * universalString UniversalString (SIZE (1..MAX)),
326 * utf8String UTF8String (SIZE (1.. MAX)),
327 * bmpString BMPString (SIZE (1..MAX)) }
330 public static final ASN1Type attributeValue = new ASN1Type(ASN1Constants.TAG_PRINTABLESTRING) {
332 public boolean checkTag(int tag) {
333 return true;
336 public Object decode(BerInputStream in) throws IOException {
337 // FIXME what about constr???
338 String str = null;
339 if (DirectoryString.ASN1.checkTag(in.tag)) {
340 // has string representation
341 str = (String) DirectoryString.ASN1.decode(in);
342 } else {
343 // gets octets only
344 in.readContent();
347 byte[] bytesEncoded = new byte[in.getOffset() - in.getTagOffset()];
348 System.arraycopy(in.getBuffer(), in.getTagOffset(), bytesEncoded,
349 0, bytesEncoded.length);
351 return new AttributeValue(str, bytesEncoded, in.tag);
354 @Override public Object getDecodedObject(BerInputStream in) throws IOException {
355 // stub to avoid wrong decoder usage
356 throw new RuntimeException("AttributeValue getDecodedObject MUST NOT be invoked");
360 // Encode
362 public void encodeASN(BerOutputStream out) {
363 AttributeValue av = (AttributeValue) out.content;
365 if (av.encoded != null) {
366 out.content = av.encoded;
367 out.encodeANY();
368 } else {
369 out.encodeTag(av.getTag());
370 out.content = av.bytes;
371 out.encodeString();
375 public void setEncodingContent(BerOutputStream out) {
376 AttributeValue av = (AttributeValue) out.content;
378 if (av.encoded != null) {
379 out.length = av.encoded.length;
380 } else {
381 if (av.getTag() == ASN1Constants.TAG_UTF8STRING) {
382 out.content = av.rawString;
383 ASN1StringType.UTF8STRING.setEncodingContent(out);
384 av.bytes = (byte[]) out.content;
385 out.content = av;
386 } else {
387 av.bytes = av.rawString.getBytes(StandardCharsets.UTF_8);
388 out.length = av.bytes.length;
393 public void encodeContent(BerOutputStream out) {
394 // stub to avoid wrong encoder usage
395 throw new RuntimeException("AttributeValue encodeContent MUST NOT be invoked");
398 @Override public int getEncodedLength(BerOutputStream out) { //FIXME name
399 AttributeValue av = (AttributeValue) out.content;
400 if (av.encoded != null) {
401 return out.length;
402 } else {
403 return super.getEncodedLength(out);
408 public static final ASN1Sequence ASN1 = new ASN1Sequence(new ASN1Type[] {
409 ASN1Oid.getInstance(), attributeValue }) {
411 @Override protected Object getDecodedObject(BerInputStream in) throws IOException {
412 Object[] values = (Object[]) in.content;
413 return new AttributeTypeAndValue((int[]) values[0], (AttributeValue) values[1]);
416 @Override protected void getValues(Object object, Object[] values) {
417 AttributeTypeAndValue atav = (AttributeTypeAndValue) object;
418 values[0] = atav.oid.getOid();
419 values[1] = atav.value;
424 * Returns known OID or null.
426 private static ObjectIdentifier getOID(int[] oid) {
427 int index = hashIntArray(oid) % CAPACITY;
429 // look for OID in the pool
430 ObjectIdentifier[] list = KNOWN_OIDS[index];
431 for (int i = 0; list[i] != null; i++) {
432 if (Arrays.equals(oid, list[i].getOid())) {
433 return list[i];
436 return null;
440 * Adds known OID to pool.
441 * for static AttributeTypeAndValue initialization only
443 private static void addOID(ObjectIdentifier oid) {
444 int[] newOid = oid.getOid();
445 int index = hashIntArray(newOid) % CAPACITY;
447 // look for OID in the pool
448 ObjectIdentifier[] list = KNOWN_OIDS[index];
449 int i = 0;
450 for (; list[i] != null; i++) {
451 // check wrong static initialization: no duplicate OIDs
452 if (Arrays.equals(newOid, list[i].getOid())) {
453 throw new Error("ObjectIdentifier: invalid static initialization; " +
454 "duplicate OIDs: " + oid.getName() + " " + list[i].getName());
458 // check : to avoid NPE
459 if (i == (CAPACITY - 1)) {
460 throw new Error("ObjectIdentifier: invalid static initialization; " +
461 "small OID pool capacity");
463 list[i] = oid;
467 * Returns hash for array of integers.
469 private static int hashIntArray(int[] oid) {
470 int intHash = 0;
471 for (int i = 0; i < oid.length && i < 4; i++) {
472 intHash += oid[i] << (8 * i); //TODO what about to find better one?
474 return intHash & 0x7FFFFFFF; // only positive