146972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro/* 246972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro * Licensed to the Apache Software Foundation (ASF) under one or more 346972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro * contributor license agreements. See the NOTICE file distributed with 446972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro * this work for additional information regarding copyright ownership. 546972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro * The ASF licenses this file to You under the Apache License, Version 2.0 646972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro * (the "License"); you may not use this file except in compliance with 746972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro * the License. You may obtain a copy of the License at 846972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro * 946972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro * http://www.apache.org/licenses/LICENSE-2.0 1046972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro * 1146972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro * Unless required by applicable law or agreed to in writing, software 1246972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro * distributed under the License is distributed on an "AS IS" BASIS, 1346972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1446972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro * See the License for the specific language governing permissions and 1546972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro * limitations under the License. 1646972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro */ 1746972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 1846972b2d825a2368706e7d2210559ca18fc2b332Sergio Giropackage org.apache.http.conn.ssl; 1946972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 2046972b2d825a2368706e7d2210559ca18fc2b332Sergio Giroimport java.util.ArrayList; 2146972b2d825a2368706e7d2210559ca18fc2b332Sergio Giroimport java.util.Collections; 2246972b2d825a2368706e7d2210559ca18fc2b332Sergio Giroimport java.util.List; 2346972b2d825a2368706e7d2210559ca18fc2b332Sergio Giroimport javax.security.auth.x500.X500Principal; 2446972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 2546972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro/** 2646972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro * A distinguished name (DN) parser. This parser only supports extracting a 2746972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro * string value from a DN. It doesn't support values in the hex-string style. 2846972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro * 2946972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro * @hide 3046972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro */ 3146972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro@Deprecated 32ab72367506bdc9ce97db4ce3714ff65cedfa5e05Sergio Girofinal class AndroidDistinguishedNameParser { 3346972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro private final String dn; 3446972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro private final int length; 3546972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro private int pos; 3646972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro private int beg; 3746972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro private int end; 3846972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 3946972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro /** tmp vars to store positions of the currently parsed item */ 4046972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro private int cur; 4146972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 4246972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro /** distinguished name chars */ 4346972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro private char[] chars; 4446972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 45ab72367506bdc9ce97db4ce3714ff65cedfa5e05Sergio Giro public AndroidDistinguishedNameParser(X500Principal principal) { 4646972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // RFC2253 is used to ensure we get attributes in the reverse 4746972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // order of the underlying ASN.1 encoding, so that the most 4846972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // significant values of repeated attributes occur first. 4946972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro this.dn = principal.getName(X500Principal.RFC2253); 5046972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro this.length = this.dn.length(); 5146972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 5246972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 5346972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // gets next attribute type: (ALPHA 1*keychar) / oid 5446972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro private String nextAT() { 5546972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // skip preceding space chars, they can present after 5646972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // comma or semicolon (compatibility with RFC 1779) 5746972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro for (; pos < length && chars[pos] == ' '; pos++) { 5846972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 5946972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro if (pos == length) { 6046972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro return null; // reached the end of DN 6146972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 6246972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 6346972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // mark the beginning of attribute type 6446972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro beg = pos; 6546972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 6646972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // attribute type chars 6746972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro pos++; 6846972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro for (; pos < length && chars[pos] != '=' && chars[pos] != ' '; pos++) { 6946972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // we don't follow exact BNF syntax here: 7046972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // accept any char except space and '=' 7146972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 7246972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro if (pos >= length) { 7346972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro throw new IllegalStateException("Unexpected end of DN: " + dn); 7446972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 7546972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 7646972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // mark the end of attribute type 7746972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro end = pos; 7846972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 7946972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // skip trailing space chars between attribute type and '=' 8046972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // (compatibility with RFC 1779) 8146972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro if (chars[pos] == ' ') { 8246972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro for (; pos < length && chars[pos] != '=' && chars[pos] == ' '; pos++) { 8346972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 8446972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 8546972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro if (chars[pos] != '=' || pos == length) { 8646972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro throw new IllegalStateException("Unexpected end of DN: " + dn); 8746972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 8846972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 8946972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 9046972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro pos++; //skip '=' char 9146972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 9246972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // skip space chars between '=' and attribute value 9346972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // (compatibility with RFC 1779) 9446972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro for (; pos < length && chars[pos] == ' '; pos++) { 9546972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 9646972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 9746972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // in case of oid attribute type skip its prefix: "oid." or "OID." 9846972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // (compatibility with RFC 1779) 9946972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro if ((end - beg > 4) && (chars[beg + 3] == '.') 10046972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro && (chars[beg] == 'O' || chars[beg] == 'o') 10146972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro && (chars[beg + 1] == 'I' || chars[beg + 1] == 'i') 10246972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro && (chars[beg + 2] == 'D' || chars[beg + 2] == 'd')) { 10346972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro beg += 4; 10446972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 10546972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 10646972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro return new String(chars, beg, end - beg); 10746972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 10846972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 10946972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // gets quoted attribute value: QUOTATION *( quotechar / pair ) QUOTATION 11046972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro private String quotedAV() { 11146972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro pos++; 11246972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro beg = pos; 11346972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro end = beg; 11446972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro while (true) { 11546972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 11646972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro if (pos == length) { 11746972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro throw new IllegalStateException("Unexpected end of DN: " + dn); 11846972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 11946972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 12046972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro if (chars[pos] == '"') { 12146972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // enclosing quotation was found 12246972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro pos++; 12346972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro break; 12446972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } else if (chars[pos] == '\\') { 12546972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro chars[end] = getEscaped(); 12646972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } else { 12746972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // shift char: required for string with escaped chars 12846972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro chars[end] = chars[pos]; 12946972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 13046972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro pos++; 13146972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro end++; 13246972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 13346972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 13446972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // skip trailing space chars before comma or semicolon. 13546972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // (compatibility with RFC 1779) 13646972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro for (; pos < length && chars[pos] == ' '; pos++) { 13746972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 13846972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 13946972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro return new String(chars, beg, end - beg); 14046972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 14146972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 14246972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // gets hex string attribute value: "#" hexstring 14346972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro private String hexAV() { 14446972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro if (pos + 4 >= length) { 14546972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // encoded byte array must be not less then 4 c 14646972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro throw new IllegalStateException("Unexpected end of DN: " + dn); 14746972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 14846972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 14946972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro beg = pos; // store '#' position 15046972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro pos++; 15146972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro while (true) { 15246972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 15346972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // check for end of attribute value 15446972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // looks for space and component separators 15546972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro if (pos == length || chars[pos] == '+' || chars[pos] == ',' 15646972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro || chars[pos] == ';') { 15746972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro end = pos; 15846972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro break; 15946972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 16046972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 16146972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro if (chars[pos] == ' ') { 16246972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro end = pos; 16346972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro pos++; 16446972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // skip trailing space chars before comma or semicolon. 16546972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // (compatibility with RFC 1779) 16646972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro for (; pos < length && chars[pos] == ' '; pos++) { 16746972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 16846972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro break; 16946972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } else if (chars[pos] >= 'A' && chars[pos] <= 'F') { 17046972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro chars[pos] += 32; //to low case 17146972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 17246972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 17346972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro pos++; 17446972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 17546972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 17646972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // verify length of hex string 17746972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // encoded byte array must be not less then 4 and must be even number 17846972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro int hexLen = end - beg; // skip first '#' char 17946972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro if (hexLen < 5 || (hexLen & 1) == 0) { 18046972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro throw new IllegalStateException("Unexpected end of DN: " + dn); 18146972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 18246972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 18346972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // get byte encoding from string representation 18446972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro byte[] encoded = new byte[hexLen / 2]; 18546972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro for (int i = 0, p = beg + 1; i < encoded.length; p += 2, i++) { 18646972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro encoded[i] = (byte) getByte(p); 18746972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 18846972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 18946972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro return new String(chars, beg, hexLen); 19046972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 19146972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 19246972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // gets string attribute value: *( stringchar / pair ) 19346972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro private String escapedAV() { 19446972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro beg = pos; 19546972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro end = pos; 19646972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro while (true) { 19746972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro if (pos >= length) { 19846972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // the end of DN has been found 19946972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro return new String(chars, beg, end - beg); 20046972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 20146972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 20246972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro switch (chars[pos]) { 20346972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro case '+': 20446972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro case ',': 20546972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro case ';': 20646972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // separator char has been found 20746972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro return new String(chars, beg, end - beg); 20846972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro case '\\': 20946972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // escaped char 21046972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro chars[end++] = getEscaped(); 21146972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro pos++; 21246972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro break; 21346972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro case ' ': 21446972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // need to figure out whether space defines 21546972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // the end of attribute value or not 21646972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro cur = end; 21746972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 21846972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro pos++; 21946972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro chars[end++] = ' '; 22046972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 22146972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro for (; pos < length && chars[pos] == ' '; pos++) { 22246972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro chars[end++] = ' '; 22346972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 22446972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro if (pos == length || chars[pos] == ',' || chars[pos] == '+' 22546972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro || chars[pos] == ';') { 22646972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // separator char or the end of DN has been found 22746972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro return new String(chars, beg, cur - beg); 22846972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 22946972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro break; 23046972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro default: 23146972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro chars[end++] = chars[pos]; 23246972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro pos++; 23346972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 23446972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 23546972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 23646972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 23746972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // returns escaped char 23846972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro private char getEscaped() { 23946972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro pos++; 24046972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro if (pos == length) { 24146972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro throw new IllegalStateException("Unexpected end of DN: " + dn); 24246972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 24346972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 24446972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro switch (chars[pos]) { 24546972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro case '"': 24646972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro case '\\': 24746972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro case ',': 24846972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro case '=': 24946972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro case '+': 25046972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro case '<': 25146972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro case '>': 25246972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro case '#': 25346972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro case ';': 25446972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro case ' ': 25546972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro case '*': 25646972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro case '%': 25746972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro case '_': 25846972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro //FIXME: escaping is allowed only for leading or trailing space char 25946972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro return chars[pos]; 26046972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro default: 26146972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // RFC doesn't explicitly say that escaped hex pair is 26246972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // interpreted as UTF-8 char. It only contains an example of such DN. 26346972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro return getUTF8(); 26446972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 26546972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 26646972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 26746972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // decodes UTF-8 char 26846972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // see http://www.unicode.org for UTF-8 bit distribution table 26946972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro private char getUTF8() { 27046972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro int res = getByte(pos); 27146972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro pos++; //FIXME tmp 27246972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 27346972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro if (res < 128) { // one byte: 0-7F 27446972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro return (char) res; 27546972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } else if (res >= 192 && res <= 247) { 27646972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 27746972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro int count; 27846972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro if (res <= 223) { // two bytes: C0-DF 27946972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro count = 1; 28046972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro res = res & 0x1F; 28146972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } else if (res <= 239) { // three bytes: E0-EF 28246972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro count = 2; 28346972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro res = res & 0x0F; 28446972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } else { // four bytes: F0-F7 28546972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro count = 3; 28646972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro res = res & 0x07; 28746972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 28846972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 28946972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro int b; 29046972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro for (int i = 0; i < count; i++) { 29146972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro pos++; 29246972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro if (pos == length || chars[pos] != '\\') { 29346972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro return 0x3F; //FIXME failed to decode UTF-8 char - return '?' 29446972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 29546972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro pos++; 29646972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 29746972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro b = getByte(pos); 29846972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro pos++; //FIXME tmp 29946972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro if ((b & 0xC0) != 0x80) { 30046972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro return 0x3F; //FIXME failed to decode UTF-8 char - return '?' 30146972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 30246972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 30346972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro res = (res << 6) + (b & 0x3F); 30446972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 30546972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro return (char) res; 30646972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } else { 30746972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro return 0x3F; //FIXME failed to decode UTF-8 char - return '?' 30846972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 30946972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 31046972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 31146972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // Returns byte representation of a char pair 31246972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // The char pair is composed of DN char in 31346972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // specified 'position' and the next char 31446972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // According to BNF syntax: 31546972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // hexchar = DIGIT / "A" / "B" / "C" / "D" / "E" / "F" 31646972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // / "a" / "b" / "c" / "d" / "e" / "f" 31746972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro private int getByte(int position) { 31846972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro if (position + 1 >= length) { 31946972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro throw new IllegalStateException("Malformed DN: " + dn); 32046972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 32146972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 32246972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro int b1, b2; 32346972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 32446972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro b1 = chars[position]; 32546972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro if (b1 >= '0' && b1 <= '9') { 32646972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro b1 = b1 - '0'; 32746972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } else if (b1 >= 'a' && b1 <= 'f') { 32846972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro b1 = b1 - 87; // 87 = 'a' - 10 32946972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } else if (b1 >= 'A' && b1 <= 'F') { 33046972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro b1 = b1 - 55; // 55 = 'A' - 10 33146972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } else { 33246972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro throw new IllegalStateException("Malformed DN: " + dn); 33346972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 33446972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 33546972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro b2 = chars[position + 1]; 33646972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro if (b2 >= '0' && b2 <= '9') { 33746972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro b2 = b2 - '0'; 33846972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } else if (b2 >= 'a' && b2 <= 'f') { 33946972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro b2 = b2 - 87; // 87 = 'a' - 10 34046972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } else if (b2 >= 'A' && b2 <= 'F') { 34146972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro b2 = b2 - 55; // 55 = 'A' - 10 34246972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } else { 34346972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro throw new IllegalStateException("Malformed DN: " + dn); 34446972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 34546972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 34646972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro return (b1 << 4) + b2; 34746972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 34846972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 34946972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro /** 35046972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro * Parses the DN and returns the most significant attribute value 35146972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro * for an attribute type, or null if none found. 35246972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro * 35346972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro * @param attributeType attribute type to look for (e.g. "ca") 35446972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro */ 35546972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro public String findMostSpecific(String attributeType) { 35646972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // Initialize internal state. 35746972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro pos = 0; 35846972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro beg = 0; 35946972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro end = 0; 36046972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro cur = 0; 36146972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro chars = dn.toCharArray(); 36246972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 36346972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro String attType = nextAT(); 36446972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro if (attType == null) { 36546972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro return null; 36646972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 36746972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro while (true) { 36846972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro String attValue = ""; 36946972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 37046972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro if (pos == length) { 37146972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro return null; 37246972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 37346972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 37446972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro switch (chars[pos]) { 37546972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro case '"': 37646972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro attValue = quotedAV(); 37746972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro break; 37846972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro case '#': 37946972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro attValue = hexAV(); 38046972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro break; 38146972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro case '+': 38246972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro case ',': 38346972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro case ';': // compatibility with RFC 1779: semicolon can separate RDNs 38446972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro //empty attribute value 38546972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro break; 38646972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro default: 38746972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro attValue = escapedAV(); 38846972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 38946972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 39046972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // Values are ordered from most specific to least specific 39146972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // due to the RFC2253 formatting. So take the first match 39246972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // we see. 39346972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro if (attributeType.equalsIgnoreCase(attType)) { 39446972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro return attValue; 39546972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 39646972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 39746972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro if (pos >= length) { 39846972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro return null; 39946972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 40046972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 40146972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro if (chars[pos] == ',' || chars[pos] == ';') { 40246972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } else if (chars[pos] != '+') { 40346972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro throw new IllegalStateException("Malformed DN: " + dn); 40446972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 40546972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 40646972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro pos++; 40746972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro attType = nextAT(); 40846972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro if (attType == null) { 40946972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro throw new IllegalStateException("Malformed DN: " + dn); 41046972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 41146972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 41246972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 41346972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 41446972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro /** 41546972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro * Parses the DN and returns all values for an attribute type, in 41646972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro * the order of decreasing significance (most significant first). 41746972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro * 41846972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro * @param attributeType attribute type to look for (e.g. "ca") 41946972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro */ 42046972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro public List<String> getAllMostSpecificFirst(String attributeType) { 42146972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // Initialize internal state. 42246972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro pos = 0; 42346972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro beg = 0; 42446972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro end = 0; 42546972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro cur = 0; 42646972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro chars = dn.toCharArray(); 42746972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro List<String> result = Collections.emptyList(); 42846972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 42946972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro String attType = nextAT(); 43046972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro if (attType == null) { 43146972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro return result; 43246972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 43346972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro while (pos < length) { 43446972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro String attValue = ""; 43546972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 43646972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro switch (chars[pos]) { 43746972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro case '"': 43846972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro attValue = quotedAV(); 43946972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro break; 44046972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro case '#': 44146972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro attValue = hexAV(); 44246972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro break; 44346972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro case '+': 44446972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro case ',': 44546972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro case ';': // compatibility with RFC 1779: semicolon can separate RDNs 44646972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro //empty attribute value 44746972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro break; 44846972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro default: 44946972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro attValue = escapedAV(); 45046972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 45146972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 45246972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // Values are ordered from most specific to least specific 45346972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // due to the RFC2253 formatting. So take the first match 45446972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro // we see. 45546972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro if (attributeType.equalsIgnoreCase(attType)) { 45646972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro if (result.isEmpty()) { 45746972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro result = new ArrayList<String>(); 45846972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 45946972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro result.add(attValue); 46046972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 46146972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 46246972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro if (pos >= length) { 46346972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro break; 46446972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 46546972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 46646972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro if (chars[pos] == ',' || chars[pos] == ';') { 46746972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } else if (chars[pos] != '+') { 46846972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro throw new IllegalStateException("Malformed DN: " + dn); 46946972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 47046972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 47146972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro pos++; 47246972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro attType = nextAT(); 47346972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro if (attType == null) { 47446972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro throw new IllegalStateException("Malformed DN: " + dn); 47546972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 47646972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 47746972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro 47846972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro return result; 47946972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro } 48046972b2d825a2368706e7d2210559ca18fc2b332Sergio Giro} 481