/jdk-11.0.2/src/java.base/sun/security/util/DerIndefLenConverter.java

https://github.com/zxiaofan/JDK · Java · 357 lines · 226 code · 39 blank · 92 comment · 69 complexity · 33f29253a2853d00ce511346b0b64cf0 MD5 · raw file

  1. /*
  2. * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
  3. * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  4. *
  5. *
  6. *
  7. *
  8. *
  9. *
  10. *
  11. *
  12. *
  13. *
  14. *
  15. *
  16. *
  17. *
  18. *
  19. *
  20. *
  21. *
  22. *
  23. *
  24. */
  25. package sun.security.util;
  26. import java.io.IOException;
  27. import java.util.ArrayList;
  28. /**
  29. * A package private utility class to convert indefinite length DER
  30. * encoded byte arrays to definite length DER encoded byte arrays.
  31. *
  32. * This assumes that the basic data structure is "tag, length, value"
  33. * triplet. In the case where the length is "indefinite", terminating
  34. * end-of-contents bytes are expected.
  35. *
  36. * @author Hemma Prafullchandra
  37. */
  38. class DerIndefLenConverter {
  39. private static final int TAG_MASK = 0x1f; // bits 5-1
  40. private static final int FORM_MASK = 0x20; // bits 6
  41. private static final int CLASS_MASK = 0xC0; // bits 8 and 7
  42. private static final int LEN_LONG = 0x80; // bit 8 set
  43. private static final int LEN_MASK = 0x7f; // bits 7 - 1
  44. private static final int SKIP_EOC_BYTES = 2;
  45. private byte[] data, newData;
  46. private int newDataPos, dataPos, dataSize, index;
  47. private int unresolved = 0;
  48. private ArrayList<Object> ndefsList = new ArrayList<Object>();
  49. private int numOfTotalLenBytes = 0;
  50. private boolean isEOC(int tag) {
  51. return (((tag & TAG_MASK) == 0x00) && // EOC
  52. ((tag & FORM_MASK) == 0x00) && // primitive
  53. ((tag & CLASS_MASK) == 0x00)); // universal
  54. }
  55. // if bit 8 is set then it implies either indefinite length or long form
  56. static boolean isLongForm(int lengthByte) {
  57. return ((lengthByte & LEN_LONG) == LEN_LONG);
  58. }
  59. /*
  60. * Default package private constructor
  61. */
  62. DerIndefLenConverter() { }
  63. /**
  64. * Checks whether the given length byte is of the form
  65. * <em>Indefinite</em>.
  66. *
  67. * @param lengthByte the length byte from a DER encoded
  68. * object.
  69. * @return true if the byte is of Indefinite form otherwise
  70. * returns false.
  71. */
  72. static boolean isIndefinite(int lengthByte) {
  73. return (isLongForm(lengthByte) && ((lengthByte & LEN_MASK) == 0));
  74. }
  75. /**
  76. * Parse the tag and if it is an end-of-contents tag then
  77. * add the current position to the <code>eocList</code> vector.
  78. */
  79. private void parseTag() throws IOException {
  80. if (dataPos == dataSize)
  81. return;
  82. if (isEOC(data[dataPos]) && (data[dataPos + 1] == 0)) {
  83. int numOfEncapsulatedLenBytes = 0;
  84. Object elem = null;
  85. int index;
  86. for (index = ndefsList.size()-1; index >= 0; index--) {
  87. // Determine the first element in the vector that does not
  88. // have a matching EOC
  89. elem = ndefsList.get(index);
  90. if (elem instanceof Integer) {
  91. break;
  92. } else {
  93. numOfEncapsulatedLenBytes += ((byte[])elem).length - 3;
  94. }
  95. }
  96. if (index < 0) {
  97. throw new IOException("EOC does not have matching " +
  98. "indefinite-length tag");
  99. }
  100. int sectionLen = dataPos - ((Integer)elem).intValue() +
  101. numOfEncapsulatedLenBytes;
  102. byte[] sectionLenBytes = getLengthBytes(sectionLen);
  103. ndefsList.set(index, sectionLenBytes);
  104. unresolved--;
  105. // Add the number of bytes required to represent this section
  106. // to the total number of length bytes,
  107. // and subtract the indefinite-length tag (1 byte) and
  108. // EOC bytes (2 bytes) for this section
  109. numOfTotalLenBytes += (sectionLenBytes.length - 3);
  110. }
  111. dataPos++;
  112. }
  113. /**
  114. * Write the tag and if it is an end-of-contents tag
  115. * then skip the tag and its 1 byte length of zero.
  116. */
  117. private void writeTag() {
  118. if (dataPos == dataSize)
  119. return;
  120. int tag = data[dataPos++];
  121. if (isEOC(tag) && (data[dataPos] == 0)) {
  122. dataPos++; // skip length
  123. writeTag();
  124. } else
  125. newData[newDataPos++] = (byte)tag;
  126. }
  127. /**
  128. * Parse the length and if it is an indefinite length then add
  129. * the current position to the <code>ndefsList</code> vector.
  130. */
  131. private int parseLength() throws IOException {
  132. int curLen = 0;
  133. if (dataPos == dataSize)
  134. return curLen;
  135. int lenByte = data[dataPos++] & 0xff;
  136. if (isIndefinite(lenByte)) {
  137. ndefsList.add(dataPos);
  138. unresolved++;
  139. return curLen;
  140. }
  141. if (isLongForm(lenByte)) {
  142. lenByte &= LEN_MASK;
  143. if (lenByte > 4) {
  144. throw new IOException("Too much data");
  145. }
  146. if ((dataSize - dataPos) < (lenByte + 1)) {
  147. throw new IOException("Too little data");
  148. }
  149. for (int i = 0; i < lenByte; i++) {
  150. curLen = (curLen << 8) + (data[dataPos++] & 0xff);
  151. }
  152. if (curLen < 0) {
  153. throw new IOException("Invalid length bytes");
  154. }
  155. } else {
  156. curLen = (lenByte & LEN_MASK);
  157. }
  158. return curLen;
  159. }
  160. /**
  161. * Write the length and if it is an indefinite length
  162. * then calculate the definite length from the positions
  163. * of the indefinite length and its matching EOC terminator.
  164. * Then, write the value.
  165. */
  166. private void writeLengthAndValue() throws IOException {
  167. if (dataPos == dataSize)
  168. return;
  169. int curLen = 0;
  170. int lenByte = data[dataPos++] & 0xff;
  171. if (isIndefinite(lenByte)) {
  172. byte[] lenBytes = (byte[])ndefsList.get(index++);
  173. System.arraycopy(lenBytes, 0, newData, newDataPos,
  174. lenBytes.length);
  175. newDataPos += lenBytes.length;
  176. return;
  177. }
  178. if (isLongForm(lenByte)) {
  179. lenByte &= LEN_MASK;
  180. for (int i = 0; i < lenByte; i++) {
  181. curLen = (curLen << 8) + (data[dataPos++] & 0xff);
  182. }
  183. if (curLen < 0) {
  184. throw new IOException("Invalid length bytes");
  185. }
  186. } else {
  187. curLen = (lenByte & LEN_MASK);
  188. }
  189. writeLength(curLen);
  190. writeValue(curLen);
  191. }
  192. private void writeLength(int curLen) {
  193. if (curLen < 128) {
  194. newData[newDataPos++] = (byte)curLen;
  195. } else if (curLen < (1 << 8)) {
  196. newData[newDataPos++] = (byte)0x81;
  197. newData[newDataPos++] = (byte)curLen;
  198. } else if (curLen < (1 << 16)) {
  199. newData[newDataPos++] = (byte)0x82;
  200. newData[newDataPos++] = (byte)(curLen >> 8);
  201. newData[newDataPos++] = (byte)curLen;
  202. } else if (curLen < (1 << 24)) {
  203. newData[newDataPos++] = (byte)0x83;
  204. newData[newDataPos++] = (byte)(curLen >> 16);
  205. newData[newDataPos++] = (byte)(curLen >> 8);
  206. newData[newDataPos++] = (byte)curLen;
  207. } else {
  208. newData[newDataPos++] = (byte)0x84;
  209. newData[newDataPos++] = (byte)(curLen >> 24);
  210. newData[newDataPos++] = (byte)(curLen >> 16);
  211. newData[newDataPos++] = (byte)(curLen >> 8);
  212. newData[newDataPos++] = (byte)curLen;
  213. }
  214. }
  215. private byte[] getLengthBytes(int curLen) {
  216. byte[] lenBytes;
  217. int index = 0;
  218. if (curLen < 128) {
  219. lenBytes = new byte[1];
  220. lenBytes[index++] = (byte)curLen;
  221. } else if (curLen < (1 << 8)) {
  222. lenBytes = new byte[2];
  223. lenBytes[index++] = (byte)0x81;
  224. lenBytes[index++] = (byte)curLen;
  225. } else if (curLen < (1 << 16)) {
  226. lenBytes = new byte[3];
  227. lenBytes[index++] = (byte)0x82;
  228. lenBytes[index++] = (byte)(curLen >> 8);
  229. lenBytes[index++] = (byte)curLen;
  230. } else if (curLen < (1 << 24)) {
  231. lenBytes = new byte[4];
  232. lenBytes[index++] = (byte)0x83;
  233. lenBytes[index++] = (byte)(curLen >> 16);
  234. lenBytes[index++] = (byte)(curLen >> 8);
  235. lenBytes[index++] = (byte)curLen;
  236. } else {
  237. lenBytes = new byte[5];
  238. lenBytes[index++] = (byte)0x84;
  239. lenBytes[index++] = (byte)(curLen >> 24);
  240. lenBytes[index++] = (byte)(curLen >> 16);
  241. lenBytes[index++] = (byte)(curLen >> 8);
  242. lenBytes[index++] = (byte)curLen;
  243. }
  244. return lenBytes;
  245. }
  246. // Returns the number of bytes needed to represent the given length
  247. // in ASN.1 notation
  248. private int getNumOfLenBytes(int len) {
  249. int numOfLenBytes = 0;
  250. if (len < 128) {
  251. numOfLenBytes = 1;
  252. } else if (len < (1 << 8)) {
  253. numOfLenBytes = 2;
  254. } else if (len < (1 << 16)) {
  255. numOfLenBytes = 3;
  256. } else if (len < (1 << 24)) {
  257. numOfLenBytes = 4;
  258. } else {
  259. numOfLenBytes = 5;
  260. }
  261. return numOfLenBytes;
  262. }
  263. /**
  264. * Parse the value;
  265. */
  266. private void parseValue(int curLen) {
  267. dataPos += curLen;
  268. }
  269. /**
  270. * Write the value;
  271. */
  272. private void writeValue(int curLen) {
  273. for (int i=0; i < curLen; i++)
  274. newData[newDataPos++] = data[dataPos++];
  275. }
  276. /**
  277. * Converts a indefinite length DER encoded byte array to
  278. * a definte length DER encoding.
  279. *
  280. * @param indefData the byte array holding the indefinite
  281. * length encoding.
  282. * @return the byte array containing the definite length
  283. * DER encoding.
  284. * @exception IOException on parsing or re-writing errors.
  285. */
  286. byte[] convert(byte[] indefData) throws IOException {
  287. data = indefData;
  288. dataPos=0; index=0;
  289. dataSize = data.length;
  290. int len=0;
  291. int unused = 0;
  292. // parse and set up the vectors of all the indefinite-lengths
  293. while (dataPos < dataSize) {
  294. parseTag();
  295. len = parseLength();
  296. parseValue(len);
  297. if (unresolved == 0) {
  298. unused = dataSize - dataPos;
  299. dataSize = dataPos;
  300. break;
  301. }
  302. }
  303. if (unresolved != 0) {
  304. throw new IOException("not all indef len BER resolved");
  305. }
  306. newData = new byte[dataSize + numOfTotalLenBytes + unused];
  307. dataPos=0; newDataPos=0; index=0;
  308. // write out the new byte array replacing all the indefinite-lengths
  309. // and EOCs
  310. while (dataPos < dataSize) {
  311. writeTag();
  312. writeLengthAndValue();
  313. }
  314. System.arraycopy(indefData, dataSize,
  315. newData, dataSize + numOfTotalLenBytes, unused);
  316. return newData;
  317. }
  318. }