/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @author Alexander V. Esin * @version $Revision$ */ /* * Imported by CG 20090319 based on Apache Harmony ("enhanced") revision 541025. */ package org.apache.harmony.security.x501; import java.io.IOException; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Locale; import javax.security.auth.x500.X500Principal; import org.apache.harmony.security.asn1.ASN1SequenceOf; import org.apache.harmony.security.asn1.ASN1SetOf; import org.apache.harmony.security.asn1.BerInputStream; import org.apache.harmony.security.asn1.DerInputStream; import org.apache.harmony.security.x509.DNParser; /** * X.501 Name */ public class Name { //ASN.1 DER encoding of Name private volatile byte[] encoded; // RFC1779 string private String rfc1779String; // RFC2253 string private String rfc2253String; //CANONICAL string private String canonicalString; //Collection of RDNs private List rdn; /** * Creates new <code>Name</code> instance from its DER encoding * * @param encoding - ASN.1 DER encoding * @throws IOException - if encoding is wrong */ public Name(byte[] encoding) throws IOException { DerInputStream in = new DerInputStream(encoding); if (in.getEndOffset() != encoding.length) { throw new IOException("Wrong content length"); } ASN1.decode(in); this.rdn = (List) in.content; } /** * Creates new <code>Name</code> instance * * @param name - Name as String * @throws IOException - if string is wrong */ public Name(String name) throws IOException { rdn = new DNParser(name).parse(); } // Creates Name instance private Name(List rdn) { this.rdn = rdn; } /** * Returns <code>X500Principal</code> instance corresponding to this * <code>Name</code> instance * * @return equivalent X500Principal object */ public X500Principal getX500Principal(){ return new X500Principal(getName0(X500Principal.RFC2253)); } /** * Returns Relative Distinguished Name as <code>String</code> according * the format requested * * @param format * Name format requested * @return Relative Distinguished Name as <code>String</code> according * the format requested */ public String getName(String format) { // // check X500Principal constants first // if (X500Principal.RFC1779.equals(format)) { if (rfc1779String == null) { rfc1779String = getName0(format); } return rfc1779String; } else if (X500Principal.RFC2253.equals(format)) { if (rfc2253String == null) { rfc2253String = getName0(format); } return rfc2253String; } else if (X500Principal.CANONICAL.equals(format)) { if (canonicalString == null) { canonicalString = getName0(format); } return canonicalString; } // // compare ignore case // else if (X500Principal.RFC1779.equalsIgnoreCase(format)) { if (rfc1779String == null) { rfc1779String = getName0(X500Principal.RFC1779); } return rfc1779String; } else if (X500Principal.RFC2253.equalsIgnoreCase(format)) { if (rfc2253String == null) { rfc2253String = getName0(X500Principal.RFC2253); } return rfc2253String; } else if (X500Principal.CANONICAL.equalsIgnoreCase(format)) { if (canonicalString == null) { canonicalString = getName0(X500Principal.CANONICAL); } return canonicalString; } else { throw new IllegalArgumentException("Illegal format: " + format); } } /** * Returns Relative Distinguished Name as <code>String</code> according * the format requested, format is int value * * @param format * Name format requested * @return Relative Distinguished Name as <code>String</code> according * the format requested */ private String getName0(String format) { StringBuffer name = new StringBuffer(); // starting with the last element and moving to the first. for (int i = rdn.size() - 1; i >= 0; i--) { List atavList = (List) rdn.get(i); if (X500Principal.CANONICAL == format) { List sortedList = new LinkedList(atavList); Collections.sort(sortedList, new AttributeTypeAndValueComparator()); atavList = sortedList; } // Relative Distinguished Name to string Iterator it = atavList.iterator(); while (it.hasNext()) { AttributeTypeAndValue _ava = (AttributeTypeAndValue) it.next(); _ava.appendName(format, name); if (it.hasNext()) { // multi-valued RDN if (X500Principal.RFC1779 == format) { name.append(" + "); //$NON-NLS-1$ } else { name.append('+'); } } } if (i != 0) { name.append(','); if (format == X500Principal.RFC1779) { name.append(' '); } } } String sName = name.toString(); if (X500Principal.CANONICAL.equals(format)) { sName = sName.toLowerCase(Locale.US); } return sName; } /** * Gets encoded form of DN * * @return return encoding, no copying is performed */ public byte[] getEncoded() { if (encoded == null) { encoded = ASN1.encode(this); } return encoded; } /** * According to RFC 3280 (http://www.ietf.org/rfc/rfc3280.txt) * X.501 Name structure is defined as follows: * * Name ::= CHOICE { * RDNSequence } * * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName * * RelativeDistinguishedName ::= * SET OF AttributeTypeAndValue * */ public static final ASN1SetOf ASN1_RDN = new ASN1SetOf( AttributeTypeAndValue.ASN1); public static final ASN1SequenceOf ASN1 = new ASN1SequenceOf(ASN1_RDN) { public Object getDecodedObject(BerInputStream in) { return new Name((List) in.content); } public Collection getValues(Object object) { return ((Name) object).rdn; //FIXME what about get method? } }; }