// --- BEGIN COPYRIGHT BLOCK --- // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; version 2 of the License. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with this program; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. // // (C) 2007 Red Hat, Inc. // All rights reserved. // --- END COPYRIGHT BLOCK --- package netscape.security.x509; import java.io.IOException; import java.util.StringTokenizer; import netscape.security.util.DerOutputStream; import netscape.security.util.DerValue; /** * This class implements the IPAddressName as required by the GeneralNames * ASN.1 object. * * @see GeneralName * @see GeneralNameInterface * @see GeneralNames * * @version 1.2 * * @author Amit Kapoor * @author Hemma Prafullchandra */ public class IPAddressName implements GeneralNameInterface { /** * */ private static final long serialVersionUID = -4240184399679453666L; private byte[] address; /** * Create the IPAddressName object from the passed encoded Der value. * * @param derValue the encoded DER IPAddressName. * @exception IOException on error. */ public IPAddressName(DerValue derValue) throws IOException { address = derValue.getOctetString(); } /** * Create the IPAddressName object with the specified name. * * @param name the IPAddressName. */ public IPAddressName(byte[] address) { this.address = address; } protected static final char IPv4_LEN = 4; protected static final char IPv6_LEN = 16; protected static final IPAddr IPv4 = new IPv4Addr(); protected static final IPAddr IPv6 = new IPv6Addr(); /** * Create the IPAddressName object with a string representing the * ip address and a string representing the netmask, with encoding * having ip address encoding followed by the netmask encoding. * This form is needed for name constraints extension. * * @param s the ip address in the format: n.n.n.n or x:x:x:x:x:x:x:x (RFC 1884) * @param netmask the netmask address in the format: n.n.n.n or x:x:x:x:x:x:x:x (RFC 1884) */ public IPAddressName(String s, String netmask) { // Based on PKIX RFC2459. IPAddress has // 8 bytes (instead of 4 bytes) in the // context of NameConstraints IPAddr ipAddr = null; if (s.indexOf(':') != -1) { ipAddr = IPv6; address = new byte[IPv6_LEN * 2]; } else { ipAddr = IPv4; address = new byte[IPv4_LEN * 2]; } StringTokenizer st = new StringTokenizer(s, ","); int numFilled = ipAddr.getIPAddr(st.nextToken(), address, 0); if (st.hasMoreTokens()) { ipAddr.getIPAddr(st.nextToken(), address, numFilled); } else { for (int i = numFilled; i < address.length; i++) address[i] = (byte) 0xff; } } /** * Create the IPAddressName object with a string representing the * ip address. * * @param s the ip address in the format: n.n.n.n or x:x:x:x:x:x:x:x */ public IPAddressName(String s) { IPAddr ipAddr = null; if (s.indexOf(':') != -1) { ipAddr = IPv6; address = new byte[IPv6_LEN]; } else { ipAddr = IPv4; address = new byte[IPv4_LEN]; } ipAddr.getIPAddr(s, address, 0); } /** * Return the type of the GeneralName. */ public int getType() { return (GeneralNameInterface.NAME_IP); } /** * Encode the IPAddress name into the DerOutputStream. * * @param out the DER stream to encode the IPAddressName to. * @exception IOException on encoding errors. */ public void encode(DerOutputStream out) throws IOException { out.putOctetString(address); } /** * Return a printable string of IPaddress */ public String toString() { if (address.length == 4) { return ("IPAddress: " + (address[0] & 0xff) + "." + (address[1] & 0xff) + "." + (address[2] & 0xff) + "." + (address[3] & 0xff)); } else { StringBuffer r = new StringBuffer("IPAddress: " + Integer.toHexString(address[0] & 0xff)); String hexString = Integer.toHexString(address[1] & 0xff); if (hexString.length() == 1) { r.append("0" + hexString); } else { r.append(hexString); } for (int i = 2; i < address.length;) { r.append(":" + Integer.toHexString(address[i] & 0xff)); hexString = Integer.toHexString(address[i + 1] & 0xff); if (hexString.length() == 1) { r.append("0" + hexString); } else { r.append(hexString); } i += 2; } return r.toString(); } } } interface IPAddr { public int getIPAddr(String s, byte[] address, int start); public int getLength(); } class IPv4Addr implements IPAddr { protected static final int IPv4_LEN = 4; /** * Gets an IP v4 address in the form n.n.n.n. */ public int getIPAddr(String s, byte[] address, int start) { StringTokenizer st = new StringTokenizer(s, "."); int nt = st.countTokens(); if (nt != IPv4_LEN) throw new InvalidIPAddressException(s); try { int end = start + nt; for (int i = start; i < end; i++) { Integer j = new Integer(st.nextToken()); address[i] = (byte) j.intValue(); } } catch (NumberFormatException e) { throw new InvalidIPAddressException(s); } return nt; } public int getLength() { return IPv4_LEN; } } class IPv6Addr implements IPAddr { /** * Gets an IP address in the forms as defined in RFC1884:
* */ public int getIPAddr(String s, byte[] address, int start) { int lastcolon = -2; int end = start + 16; int idx = start; for (int i = start; i < address.length; i++) address[i] = 0; if (s.indexOf('.') != -1) { // has n.n.n.n at the end lastcolon = s.lastIndexOf(':'); if (lastcolon == -1) throw new InvalidIPAddressException(s); end -= 4; IPAddressName.IPv4.getIPAddr( s.substring(lastcolon + 1), address, end); } try { String s1 = s; if (lastcolon != -2) s1 = s.substring(0, lastcolon + 1); int lastDoubleColon = s1.indexOf("::"); String l = s1, r = null; StringTokenizer lt = null, rt = null; if (lastDoubleColon != -1) { l = s1.substring(0, lastDoubleColon); r = s1.substring(lastDoubleColon + 2); if (l.length() == 0) l = null; if (r.length() == 0) r = null; } int at = 0; if (l != null) { lt = new StringTokenizer(l, ":", false); at += lt.countTokens(); } if (r != null) { rt = new StringTokenizer(r, ":", false); at += rt.countTokens(); } if (at > 8 || (lastcolon != -2 && (at > 6 || (lastDoubleColon == -1 && at != 6)))) throw new InvalidIPAddressException(s); if (l != null) { while (lt.hasMoreTokens()) { String tok = lt.nextToken(); int j = Integer.parseInt(tok, 16); address[idx++] = (byte) ((j >> 8) & 0xFF); address[idx++] = (byte) (j & 0xFF); } } if (r != null) { idx = end - (rt.countTokens() * 2); while (rt.hasMoreTokens()) { String tok = rt.nextToken(); int j = Integer.parseInt(tok, 16); address[idx++] = (byte) ((j >> 8) & 0xFF); address[idx++] = (byte) (j & 0xFF); } } } catch (NumberFormatException e) { throw new InvalidIPAddressException(s); } return 16; } public int getLength() { return 16; } }