IceSSL.RFC2253 Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ice Show documentation
Show all versions of ice Show documentation
Ice is a comprehensive RPC framework that helps you build distributed applications with minimal effort using familiar object-oriented idioms
// **********************************************************************
//
// Copyright (c) 2003-2018 ZeroC, Inc. All rights reserved.
//
// This copy of Ice is licensed to you under the terms described in the
// ICE_LICENSE file included in this distribution.
//
// **********************************************************************
package IceSSL;
//
// See RFC 2253 and RFC 1779.
//
class RFC2253
{
static class ParseException extends Ice.LocalException
{
public ParseException()
{
}
public ParseException(String reason)
{
this.reason = reason;
}
@Override
public String
ice_name()
{
return "RFC2253::ParseException";
}
public String reason;
}
static class RDNPair
{
String key;
String value;
}
static class RDNEntry
{
java.util.List rdn = new java.util.LinkedList();
boolean negate = false;
}
static private class ParseState
{
String data;
int pos;
}
public static java.util.List
parse(String data)
throws ParseException
{
java.util.List results = new java.util.LinkedList();
RDNEntry current = new RDNEntry();
ParseState state = new ParseState();
state.data = data;
state.pos = 0;
while(state.pos < state.data.length())
{
eatWhite(state);
if(state.pos < state.data.length() && state.data.charAt(state.pos) == '!')
{
if(!current.rdn.isEmpty())
{
throw new ParseException("negation symbol '!' must appear at start of list");
}
++state.pos;
current.negate = true;
}
current.rdn.add(parseNameComponent(state));
eatWhite(state);
if(state.pos < state.data.length() && state.data.charAt(state.pos) == ',')
{
++state.pos;
}
else if(state.pos < state.data.length() && state.data.charAt(state.pos) == ';')
{
++state.pos;
results.add(current);
current = new RDNEntry();
}
else if(state.pos < state.data.length())
{
throw new ParseException("expected ',' or ';' at `" + state.data.substring(state.pos) + "'");
}
}
if(!current.rdn.isEmpty())
{
results.add(current);
}
return results;
}
public static java.util.List
parseStrict(String data)
throws ParseException
{
java.util.List results = new java.util.LinkedList();
ParseState state = new ParseState();
state.data = data;
state.pos = 0;
while(state.pos < state.data.length())
{
results.add(parseNameComponent(state));
eatWhite(state);
if(state.pos < state.data.length() &&
(state.data.charAt(state.pos) == ',' || state.data.charAt(state.pos) == ';'))
{
++state.pos;
}
else if(state.pos < state.data.length())
{
throw new ParseException("expected ',' or ';' at `" + state.data.substring(state.pos) + "'");
}
}
return results;
}
private static RDNPair
parseNameComponent(ParseState state)
throws ParseException
{
RDNPair result = parseAttributeTypeAndValue(state);
while(state.pos < state.data.length())
{
eatWhite(state);
if(state.pos < state.data.length() && state.data.charAt(state.pos) == '+')
{
++state.pos;
}
else
{
break;
}
RDNPair p = parseAttributeTypeAndValue(state);
result.value += "+";
result.value += p.key;
result.value += '=';
result.value += p.value;
}
return result;
}
private static RDNPair
parseAttributeTypeAndValue(ParseState state)
throws ParseException
{
RDNPair p = new RDNPair();
p.key = parseAttributeType(state);
eatWhite(state);
if(state.pos >= state.data.length())
{
throw new ParseException("invalid attribute type/value pair (unexpected end of state.data)");
}
if(state.data.charAt(state.pos) != '=')
{
throw new ParseException("invalid attribute type/value pair (missing =)");
}
++state.pos;
p.value = parseAttributeValue(state);
return p;
}
private static String
parseAttributeType(ParseState state)
throws ParseException
{
eatWhite(state);
if(state.pos >= state.data.length())
{
throw new ParseException("invalid attribute type (expected end of state.data)");
}
StringBuffer result = new StringBuffer();
//
// RFC 1779.
// ::= 1*( ) | "OID." | "oid."
// ::= | "."
// RFC 2253:
// attributeType = (ALPHA 1*keychar) | oid
// keychar = ALPHA | DIGIT | "-"
// oid = 1*DIGIT *("." 1*DIGIT)
//
// In section 4 of RFC 2253 the document says:
// Implementations MUST allow an oid in the attribute type to be
// prefixed by one of the character Strings "oid." or "OID.".
//
// Here we must also check for "oid." and "OID." before parsing
// according to the ALPHA KEYCHAR* rule.
//
// First the OID case.
//
if(Character.isDigit(state.data.charAt(state.pos)) ||
(state.data.length() - state.pos >= 4 && (state.data.substring(state.pos, state.pos + 4).equals("oid.") ||
state.data.substring(state.pos, state.pos + 4).equals("OID."))))
{
if(!Character.isDigit(state.data.charAt(state.pos)))
{
result.append(state.data.substring(state.pos, state.pos + 4));
state.pos += 4;
}
while(true)
{
// 1*DIGIT
while(state.pos < state.data.length() && Character.isDigit(state.data.charAt(state.pos)))
{
result.append(state.data.charAt(state.pos));
++state.pos;
}
// "." 1*DIGIT
if(state.pos < state.data.length() && state.data.charAt(state.pos) == '.')
{
result.append(state.data.charAt(state.pos));
++state.pos;
// 1*DIGIT must follow "."
if(state.pos < state.data.length() && !Character.isDigit(state.data.charAt(state.pos)))
{
throw new ParseException("invalid attribute type (expected end of state.data)");
}
}
else
{
break;
}
}
}
else if(Character.isUpperCase(state.data.charAt(state.pos)) ||
Character.isLowerCase(state.data.charAt(state.pos)))
{
//
// The grammar is wrong in this case. It should be ALPHA
// KEYCHAR* otherwise it will not accept "O" as a valid
// attribute type.
//
result.append(state.data.charAt(state.pos));
++state.pos;
// 1* KEYCHAR
while(state.pos < state.data.length() &&
(Character.isDigit(state.data.charAt(state.pos)) ||
Character.isUpperCase(state.data.charAt(state.pos)) ||
Character.isLowerCase(state.data.charAt(state.pos)) ||
state.data.charAt(state.pos) == '-'))
{
result.append(state.data.charAt(state.pos));
++state.pos;
}
}
else
{
throw new ParseException("invalid attribute type");
}
return result.toString();
}
private static String
parseAttributeValue(ParseState state)
throws ParseException
{
eatWhite(state);
if(state.pos >= state.data.length())
{
return "";
}
//
// RFC 2253
// # hexString
//
StringBuffer result = new StringBuffer();
if(state.data.charAt(state.pos) == '#')
{
result.append(state.data.charAt(state.pos));
++state.pos;
while(true)
{
String h = parseHexPair(state, true);
if(h.length() == 0)
{
break;
}
result.append(h);
}
}
//
// RFC 2253
// QUOTATION *( quotechar | pair ) QUOTATION ; only from v2
// quotechar =
//
else if(state.data.charAt(state.pos) == '"')
{
result.append(state.data.charAt(state.pos));
++state.pos;
while(true)
{
if(state.pos >= state.data.length())
{
throw new ParseException("invalid attribute value (unexpected end of state.data)");
}
// final terminating "
if(state.data.charAt(state.pos) == '"')
{
result.append(state.data.charAt(state.pos));
++state.pos;
break;
}
// any character except '\'
else if(state.data.charAt(state.pos) != '\\')
{
result.append(state.data.charAt(state.pos));
++state.pos;
}
// pair '\'
else
{
result.append(parsePair(state));
}
}
}
//
// RFC 2253
// * (Stringchar | pair)
// Stringchar =
//
else
{
while(state.pos < state.data.length())
{
if(state.data.charAt(state.pos) == '\\')
{
result.append(parsePair(state));
}
else if(special.indexOf(state.data.charAt(state.pos)) == -1 && state.data.charAt(state.pos) != '"')
{
result.append(state.data.charAt(state.pos));
++state.pos;
}
else
{
break;
}
}
}
return result.toString();
}
//
// RFC2253:
// pair = "\" ( special | "\" | QUOTATION | hexpair )
//
private static String
parsePair(ParseState state)
throws ParseException
{
String result = "";
assert(state.data.charAt(state.pos) == '\\');
result += state.data.charAt(state.pos);
++state.pos;
if(state.pos >= state.data.length())
{
throw new ParseException("invalid escape format (unexpected end of state.data)");
}
if(special.indexOf(state.data.charAt(state.pos)) != -1 || state.data.charAt(state.pos) != '\\' ||
state.data.charAt(state.pos) != '"')
{
result += state.data.charAt(state.pos);
++state.pos;
return result;
}
return parseHexPair(state, false);
}
//
// RFC 2253
// hexpair = hexchar hexchar
//
private static String
parseHexPair(ParseState state, boolean allowEmpty)
throws ParseException
{
String result = "";
if(state.pos < state.data.length() && hexvalid.indexOf(state.data.charAt(state.pos)) != -1)
{
result += state.data.charAt(state.pos);
++state.pos;
}
if(state.pos < state.data.length() && hexvalid.indexOf(state.data.charAt(state.pos)) != -1)
{
result += state.data.charAt(state.pos);
++state.pos;
}
if(result.length() != 2)
{
if(allowEmpty && result.length() == 0)
{
return result;
}
throw new ParseException("invalid hex format");
}
return result;
}
//
// RFC 2253:
//
// Implementations MUST allow for space (' ' ASCII 32) characters to be
// present between name-component and ',', between attributeTypeAndValue
// and '+', between attributeType and '=', and between '=' and
// attributeValue. These space characters are ignored when parsing.
//
private static void
eatWhite(ParseState state)
{
while(state.pos < state.data.length() && state.data.charAt(state.pos) == ' ')
{
++state.pos;
}
}
private final static String special = ",=+<>#;";
private final static String hexvalid = "0123456789abcdefABCDEF";
}