001 package org.apache.commons.ssl.asn1; 002 003 import java.io.ByteArrayOutputStream; 004 import java.io.IOException; 005 import java.io.OutputStream; 006 import java.math.BigInteger; 007 008 public class DERObjectIdentifier 009 extends ASN1Object { 010 String identifier; 011 012 /** 013 * return an OID from the passed in object 014 * 015 * @throws IllegalArgumentException if the object cannot be converted. 016 */ 017 public static DERObjectIdentifier getInstance( 018 Object obj) { 019 if (obj == null || obj instanceof DERObjectIdentifier) { 020 return (DERObjectIdentifier) obj; 021 } 022 023 if (obj instanceof ASN1OctetString) { 024 return new DERObjectIdentifier(((ASN1OctetString) obj).getOctets()); 025 } 026 027 if (obj instanceof ASN1TaggedObject) { 028 return getInstance(((ASN1TaggedObject) obj).getObject()); 029 } 030 031 throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); 032 } 033 034 /** 035 * return an Object Identifier from a tagged object. 036 * 037 * @param obj the tagged object holding the object we want 038 * @param explicit true if the object is meant to be explicitly 039 * tagged false otherwise. 040 * @throws IllegalArgumentException if the tagged object cannot 041 * be converted. 042 */ 043 public static DERObjectIdentifier getInstance( 044 ASN1TaggedObject obj, 045 boolean explicit) { 046 return getInstance(obj.getObject()); 047 } 048 049 050 DERObjectIdentifier( 051 byte[] bytes) { 052 StringBuffer objId = new StringBuffer(); 053 long value = 0; 054 BigInteger bigValue = null; 055 boolean first = true; 056 057 for (int i = 0; i != bytes.length; i++) { 058 int b = bytes[i] & 0xff; 059 060 if (value < 0x80000000000000L) { 061 value = value * 128 + (b & 0x7f); 062 if ((b & 0x80) == 0) // end of number reached 063 { 064 if (first) { 065 switch ((int) value / 40) { 066 case 0: 067 objId.append('0'); 068 break; 069 case 1: 070 objId.append('1'); 071 value -= 40; 072 break; 073 default: 074 objId.append('2'); 075 value -= 80; 076 } 077 first = false; 078 } 079 080 objId.append('.'); 081 objId.append(value); 082 value = 0; 083 } 084 } else { 085 if (bigValue == null) { 086 bigValue = BigInteger.valueOf(value); 087 } 088 bigValue = bigValue.shiftLeft(7); 089 bigValue = bigValue.or(BigInteger.valueOf(b & 0x7f)); 090 if ((b & 0x80) == 0) { 091 objId.append('.'); 092 objId.append(bigValue); 093 bigValue = null; 094 value = 0; 095 } 096 } 097 } 098 099 this.identifier = objId.toString(); 100 } 101 102 public DERObjectIdentifier( 103 String identifier) { 104 if (!isValidIdentifier(identifier)) { 105 throw new IllegalArgumentException("string " + identifier + " not an OID"); 106 } 107 108 this.identifier = identifier; 109 } 110 111 public String getId() { 112 return identifier; 113 } 114 115 private void writeField( 116 OutputStream out, 117 long fieldValue) 118 throws IOException { 119 if (fieldValue >= (1L << 7)) { 120 if (fieldValue >= (1L << 14)) { 121 if (fieldValue >= (1L << 21)) { 122 if (fieldValue >= (1L << 28)) { 123 if (fieldValue >= (1L << 35)) { 124 if (fieldValue >= (1L << 42)) { 125 if (fieldValue >= (1L << 49)) { 126 if (fieldValue >= (1L << 56)) { 127 out.write((int) (fieldValue >> 56) | 0x80); 128 } 129 out.write((int) (fieldValue >> 49) | 0x80); 130 } 131 out.write((int) (fieldValue >> 42) | 0x80); 132 } 133 out.write((int) (fieldValue >> 35) | 0x80); 134 } 135 out.write((int) (fieldValue >> 28) | 0x80); 136 } 137 out.write((int) (fieldValue >> 21) | 0x80); 138 } 139 out.write((int) (fieldValue >> 14) | 0x80); 140 } 141 out.write((int) (fieldValue >> 7) | 0x80); 142 } 143 out.write((int) fieldValue & 0x7f); 144 } 145 146 private void writeField( 147 OutputStream out, 148 BigInteger fieldValue) 149 throws IOException { 150 int byteCount = (fieldValue.bitLength() + 6) / 7; 151 if (byteCount == 0) { 152 out.write(0); 153 } else { 154 BigInteger tmpValue = fieldValue; 155 byte[] tmp = new byte[byteCount]; 156 for (int i = byteCount - 1; i >= 0; i--) { 157 tmp[i] = (byte) ((tmpValue.intValue() & 0x7f) | 0x80); 158 tmpValue = tmpValue.shiftRight(7); 159 } 160 tmp[byteCount - 1] &= 0x7f; 161 out.write(tmp); 162 } 163 164 } 165 166 void encode( 167 DEROutputStream out) 168 throws IOException { 169 OIDTokenizer tok = new OIDTokenizer(identifier); 170 ByteArrayOutputStream bOut = new ByteArrayOutputStream(); 171 DEROutputStream dOut = new DEROutputStream(bOut); 172 173 writeField(bOut, 174 Integer.parseInt(tok.nextToken()) * 40 175 + Integer.parseInt(tok.nextToken())); 176 177 while (tok.hasMoreTokens()) { 178 String token = tok.nextToken(); 179 if (token.length() < 18) { 180 writeField(bOut, Long.parseLong(token)); 181 } else { 182 writeField(bOut, new BigInteger(token)); 183 } 184 } 185 186 dOut.close(); 187 188 byte[] bytes = bOut.toByteArray(); 189 190 out.writeEncoded(OBJECT_IDENTIFIER, bytes); 191 } 192 193 public int hashCode() { 194 return identifier.hashCode(); 195 } 196 197 boolean asn1Equals( 198 DERObject o) { 199 if (!(o instanceof DERObjectIdentifier)) { 200 return false; 201 } 202 203 return identifier.equals(((DERObjectIdentifier) o).identifier); 204 } 205 206 public String toString() { 207 return getId(); 208 } 209 210 private static boolean isValidIdentifier( 211 String identifier) { 212 if (identifier.length() < 3 213 || identifier.charAt(1) != '.') { 214 return false; 215 } 216 217 char first = identifier.charAt(0); 218 if (first < '0' || first > '2') { 219 return false; 220 } 221 222 boolean periodAllowed = false; 223 for (int i = identifier.length() - 1; i >= 2; i--) { 224 char ch = identifier.charAt(i); 225 226 if ('0' <= ch && ch <= '9') { 227 periodAllowed = true; 228 continue; 229 } 230 231 if (ch == '.') { 232 if (!periodAllowed) { 233 return false; 234 } 235 236 periodAllowed = false; 237 continue; 238 } 239 240 return false; 241 } 242 243 return periodAllowed; 244 } 245 }