1 /* 2 * Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.jndi.ldap; 27 28 import java.io.UnsupportedEncodingException; 29 30 /** 31 * A BER encoder. 32 * 33 * @author Jagane Sundar 34 * @author Scott Seligman 35 * @author Vincent Ryan 36 */ 37 public final class BerEncoder extends Ber { 38 39 private int curSeqIndex; 40 private int seqOffset[]; 41 private static final int INITIAL_SEQUENCES = 16; 42 private static final int DEFAULT_BUFSIZE = 1024; 43 44 // When buf is full, expand its size by the following factor. 45 private static final int BUF_GROWTH_FACTOR = 8; 46 47 /** 48 * Creates a BER buffer for encoding. 49 */ 50 public BerEncoder() { 51 this(DEFAULT_BUFSIZE); 52 } 53 54 /** 55 * Creates a BER buffer of a specified size for encoding. 56 * Specify the initial bufsize. Buffer will be expanded as needed. 57 * @param bufsize The number of bytes for the buffer. 58 */ 59 public BerEncoder(int bufsize) { 60 buf = new byte[bufsize]; 61 this.bufsize = bufsize; 62 offset = 0; 63 64 seqOffset = new int[INITIAL_SEQUENCES]; 65 curSeqIndex = 0; 66 } 67 68 /** 69 * Resets encoder to state when newly constructed. Zeros out 70 * internal data structures. 71 */ 72 public void reset() { 73 while (offset > 0) { 74 buf[--offset] = 0; 75 } 76 while (curSeqIndex > 0) { 77 seqOffset[--curSeqIndex] = 0; 78 } 79 } 80 81 // ------------------ Accessor methods ------------ 82 83 /** 84 * Gets the number of encoded bytes in this BER buffer. 85 */ 86 public int getDataLen() { 87 return offset; 88 } 89 90 /** 91 * Gets the buffer that contains the BER encoding. Throws an 92 * exception if unmatched beginSeq() and endSeq() pairs were 93 * encountered. Not entire buffer contains encoded bytes. 94 * Use getDataLen() to determine number of encoded bytes. 95 * Use getBuffer(true) to get rid of excess bytes in array. 96 * @throws IllegalStateException If buffer contains unbalanced sequence. 97 */ 98 public byte[] getBuf() { 99 if (curSeqIndex != 0) { 100 throw new IllegalStateException("BER encode error: Unbalanced SEQUENCEs."); 101 } 102 return buf; // shared buffer, be careful to use this method. 103 } 104 105 /** 106 * Gets the buffer that contains the BER encoding, trimming unused bytes. 107 * 108 * @throws IllegalStateException If buffer contains unbalanced sequence. 109 */ 110 public byte[] getTrimmedBuf() { 111 int len = getDataLen(); 112 byte[] trimBuf = new byte[len]; 113 114 System.arraycopy(getBuf(), 0, trimBuf, 0, len); 115 return trimBuf; 116 } 117 118 // -------------- encoding methods ------------- 119 120 /** 121 * Begin encoding a sequence with a tag. 122 */ 123 public void beginSeq(int tag) { 124 125 // Double the size of the SEQUENCE array if it overflows 126 if (curSeqIndex >= seqOffset.length) { 127 int[] seqOffsetTmp = new int[seqOffset.length * 2]; 128 129 for (int i = 0; i < seqOffset.length; i++) { 130 seqOffsetTmp[i] = seqOffset[i]; 131 } 132 seqOffset = seqOffsetTmp; 133 } 134 135 encodeByte(tag); 136 seqOffset[curSeqIndex] = offset; 137 138 // Save space for sequence length. 139 // %%% Currently we save enough space for sequences up to 64k. 140 // For larger sequences we'll need to shift the data to the right 141 // in endSeq(). If we could instead pad the length field with 142 // zeros, it would be a big win. 143 ensureFreeBytes(3); 144 offset += 3; 145 146 curSeqIndex++; 147 } 148 149 /** 150 * Terminate a BER sequence. 151 */ 152 public void endSeq() throws EncodeException { 153 curSeqIndex--; 154 if (curSeqIndex < 0) { 155 throw new IllegalStateException("BER encode error: Unbalanced SEQUENCEs."); 156 } 157 158 int start = seqOffset[curSeqIndex] + 3; // index beyond length field 159 int len = offset - start; 160 161 if (len <= 0x7f) { 162 shiftSeqData(start, len, -2); 163 buf[seqOffset[curSeqIndex]] = (byte) len; 164 } else if (len <= 0xff) { 165 shiftSeqData(start, len, -1); 166 buf[seqOffset[curSeqIndex]] = (byte) 0x81; 167 buf[seqOffset[curSeqIndex] + 1] = (byte) len; 168 } else if (len <= 0xffff) { 169 buf[seqOffset[curSeqIndex]] = (byte) 0x82; 170 buf[seqOffset[curSeqIndex] + 1] = (byte) (len >> 8); 171 buf[seqOffset[curSeqIndex] + 2] = (byte) len; 172 } else if (len <= 0xffffff) { 173 shiftSeqData(start, len, 1); 174 buf[seqOffset[curSeqIndex]] = (byte) 0x83; 175 buf[seqOffset[curSeqIndex] + 1] = (byte) (len >> 16); 176 buf[seqOffset[curSeqIndex] + 2] = (byte) (len >> 8); 177 buf[seqOffset[curSeqIndex] + 3] = (byte) len; 178 } else { 179 throw new EncodeException("SEQUENCE too long"); 180 } 181 } 182 183 /** 184 * Shifts contents of buf in the range [start,start+len) a specified amount. 185 * Positive shift value means shift to the right. 186 */ 187 private void shiftSeqData(int start, int len, int shift) { 188 if (shift > 0) { 189 ensureFreeBytes(shift); 190 } 191 System.arraycopy(buf, start, buf, start + shift, len); 192 offset += shift; 193 } 194 195 /** 196 * Encode a single byte. 197 */ 198 public void encodeByte(int b) { 199 ensureFreeBytes(1); 200 buf[offset++] = (byte) b; 201 } 202 203 /* 204 private void deleteByte() { 205 offset--; 206 } 207 */ 208 209 210 /* 211 * Encodes an int. 212 *<blockquote><pre> 213 * BER integer ::= 0x02 berlength byte {byte}* 214 *</pre></blockquote> 215 */ 216 public void encodeInt(int i) { 217 encodeInt(i, 0x02); 218 } 219 220 /** 221 * Encodes an int and a tag. 222 *<blockquote><pre> 223 * BER integer w tag ::= tag berlength byte {byte}* 224 *</pre></blockquote> 225 */ 226 public void encodeInt(int i, int tag) { 227 int mask = 0xff800000; 228 int intsize = 4; 229 230 while( (((i & mask) == 0) || ((i & mask) == mask)) && (intsize > 1) ) { 231 intsize--; 232 i <<= 8; 233 } 234 235 encodeInt(i, tag, intsize); 236 } 237 238 // 239 // encodes an int using numbytes for the actual encoding. 240 // 241 private void encodeInt(int i, int tag, int intsize) { 242 243 // 244 // integer ::= 0x02 asnlength byte {byte}* 245 // 246 247 if (intsize > 4) { 248 throw new IllegalArgumentException("BER encode error: INTEGER too long."); 249 } 250 251 ensureFreeBytes(2 + intsize); 252 253 buf[offset++] = (byte) tag; 254 buf[offset++] = (byte) intsize; 255 256 int mask = 0xff000000; 257 258 while (intsize-- > 0) { 259 buf[offset++] = (byte) ((i & mask) >> 24); 260 i <<= 8; 261 } 262 } 263 264 /** 265 * Encodes a boolean. 266 *<blockquote><pre> 267 * BER boolean ::= 0x01 0x01 {0xff|0x00} 268 *</pre></blockquote> 269 */ 270 public void encodeBoolean(boolean b) { 271 encodeBoolean(b, ASN_BOOLEAN); 272 } 273 274 275 /** 276 * Encodes a boolean and a tag 277 *<blockquote><pre> 278 * BER boolean w TAG ::= tag 0x01 {0xff|0x00} 279 *</pre></blockquote> 280 */ 281 public void encodeBoolean(boolean b, int tag) { 282 ensureFreeBytes(3); 283 284 buf[offset++] = (byte) tag; 285 buf[offset++] = 0x01; 286 buf[offset++] = b ? (byte) 0xff : (byte) 0x00; 287 } 288 289 /** 290 * Encodes a string. 291 *<blockquote><pre> 292 * BER string ::= 0x04 strlen byte1 byte2... 293 *</pre></blockquote> 294 * The string is converted into bytes using UTF-8 or ISO-Latin-1. 295 */ 296 public void encodeString(String str, boolean encodeUTF8) 297 throws EncodeException { 298 encodeString(str, ASN_OCTET_STR, encodeUTF8); 299 } 300 301 /** 302 * Encodes a string and a tag. 303 *<blockquote><pre> 304 * BER string w TAG ::= tag strlen byte1 byte2... 305 *</pre></blockquote> 306 */ 307 public void encodeString(String str, int tag, boolean encodeUTF8) 308 throws EncodeException { 309 310 encodeByte(tag); 311 312 int i = 0; 313 int count; 314 byte[] bytes = null; 315 316 if (str == null) { 317 count = 0; 318 } else if (encodeUTF8) { 319 try { 320 bytes = str.getBytes("UTF8"); 321 count = bytes.length; 322 } catch (UnsupportedEncodingException e) { 323 throw new EncodeException("UTF8 not available on platform"); 324 } 325 } else { 326 try { 327 bytes = str.getBytes("8859_1"); 328 count = bytes.length; 329 } catch (UnsupportedEncodingException e) { 330 throw new EncodeException("8859_1 not available on platform"); 331 } 332 } 333 334 encodeLength(count); 335 336 ensureFreeBytes(count); 337 while (i < count) { 338 buf[offset++] = bytes[i++]; 339 } 340 } 341 342 /** 343 * Encodes a portion of an octet string and a tag. 344 */ 345 public void encodeOctetString(byte tb[], int tag, int tboffset, int length) 346 throws EncodeException { 347 348 encodeByte(tag); 349 encodeLength(length); 350 351 if (length > 0) { 352 ensureFreeBytes(length); 353 System.arraycopy(tb, tboffset, buf, offset, length); 354 offset += length; 355 } 356 } 357 358 /** 359 * Encodes an octet string and a tag. 360 */ 361 public void encodeOctetString(byte tb[], int tag) throws EncodeException { 362 encodeOctetString(tb, tag, 0, tb.length); 363 } 364 365 private void encodeLength(int len) throws EncodeException { 366 ensureFreeBytes(4); // worst case 367 368 if (len < 128) { 369 buf[offset++] = (byte) len; 370 } else if (len <= 0xff) { 371 buf[offset++] = (byte) 0x81; 372 buf[offset++] = (byte) len; 373 } else if (len <= 0xffff) { 374 buf[offset++] = (byte) 0x82; 375 buf[offset++] = (byte) (len >> 8); 376 buf[offset++] = (byte) (len & 0xff); 377 } else if (len <= 0xffffff) { 378 buf[offset++] = (byte) 0x83; 379 buf[offset++] = (byte) (len >> 16); 380 buf[offset++] = (byte) (len >> 8); 381 buf[offset++] = (byte) (len & 0xff); 382 } else { 383 throw new EncodeException("string too long"); 384 } 385 } 386 387 /** 388 * Encodes an array of strings. 389 */ 390 public void encodeStringArray(String strs[], boolean encodeUTF8) 391 throws EncodeException { 392 if (strs == null) 393 return; 394 for (int i = 0; i < strs.length; i++) { 395 encodeString(strs[i], encodeUTF8); 396 } 397 } 398 /* 399 private void encodeNull() { 400 401 // 402 // NULL ::= 0x05 0x00 403 // 404 encodeByte(0x05); 405 encodeByte(0x00); 406 } 407 */ 408 409 /** 410 * Ensures that there are at least "len" unused bytes in "buf". 411 * When more space is needed "buf" is expanded by a factor of 412 * BUF_GROWTH_FACTOR, then "len" bytes are added if "buf" still 413 * isn't large enough. 414 */ 415 private void ensureFreeBytes(int len) { 416 if (bufsize - offset < len) { 417 int newsize = bufsize * BUF_GROWTH_FACTOR; 418 if (newsize - offset < len) { 419 newsize += len; 420 } 421 byte newbuf[] = new byte[newsize]; 422 // Only copy bytes in the range [0, offset) 423 System.arraycopy(buf, 0, newbuf, 0, offset); 424 425 buf = newbuf; 426 bufsize = newsize; 427 } 428 } 429 }