/security/nss/cmd/lib/berparse.c

http://github.com/zpao/v8monkey · C · 407 lines · 305 code · 42 blank · 60 comment · 83 complexity · 4a6892ffc7a8fc97d195f6bc7cf3cbbd MD5 · raw file

  1. /* ***** BEGIN LICENSE BLOCK *****
  2. * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3. *
  4. * The contents of this file are subject to the Mozilla Public License Version
  5. * 1.1 (the "License"); you may not use this file except in compliance with
  6. * the License. You may obtain a copy of the License at
  7. * http://www.mozilla.org/MPL/
  8. *
  9. * Software distributed under the License is distributed on an "AS IS" basis,
  10. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11. * for the specific language governing rights and limitations under the
  12. * License.
  13. *
  14. * The Original Code is the Netscape security libraries.
  15. *
  16. * The Initial Developer of the Original Code is
  17. * Netscape Communications Corporation.
  18. * Portions created by the Initial Developer are Copyright (C) 1994-2000
  19. * the Initial Developer. All Rights Reserved.
  20. *
  21. * Contributor(s):
  22. *
  23. * Alternatively, the contents of this file may be used under the terms of
  24. * either the GNU General Public License Version 2 or later (the "GPL"), or
  25. * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  26. * in which case the provisions of the GPL or the LGPL are applicable instead
  27. * of those above. If you wish to allow use of your version of this file only
  28. * under the terms of either the GPL or the LGPL, and not to allow others to
  29. * use your version of this file under the terms of the MPL, indicate your
  30. * decision by deleting the provisions above and replace them with the notice
  31. * and other provisions required by the GPL or the LGPL. If you do not delete
  32. * the provisions above, a recipient may use your version of this file under
  33. * the terms of any one of the MPL, the GPL or the LGPL.
  34. *
  35. * ***** END LICENSE BLOCK ***** */
  36. #include "secutil.h"
  37. typedef enum {
  38. tagDone, lengthDone, leafDone, compositeDone,
  39. notDone,
  40. parseError, parseComplete
  41. } ParseState;
  42. typedef unsigned char Byte;
  43. typedef void (*ParseProc)(BERParse *h, unsigned char **buf, int *len);
  44. typedef struct {
  45. SECArb arb;
  46. int pos; /* length from global start to item start */
  47. SECArb *parent;
  48. } ParseStackElem;
  49. struct BERParseStr {
  50. PRArenaPool *his;
  51. PRArenaPool *mine;
  52. ParseProc proc;
  53. int stackDepth;
  54. ParseStackElem *stackPtr;
  55. ParseStackElem *stack;
  56. int pending; /* bytes remaining to complete this part */
  57. int pos; /* running length of consumed characters */
  58. ParseState state;
  59. PRBool keepLeaves;
  60. PRBool derOnly;
  61. BERFilterProc filter;
  62. void *filterArg;
  63. BERNotifyProc before;
  64. void *beforeArg;
  65. BERNotifyProc after;
  66. void *afterArg;
  67. };
  68. #define UNKNOWN -1
  69. static unsigned char NextChar(BERParse *h, unsigned char **buf, int *len)
  70. {
  71. unsigned char c = *(*buf)++;
  72. (*len)--;
  73. h->pos++;
  74. if (h->filter)
  75. (*h->filter)(h->filterArg, &c, 1);
  76. return c;
  77. }
  78. static void ParseTag(BERParse *h, unsigned char **buf, int *len)
  79. {
  80. SECArb* arb = &(h->stackPtr->arb);
  81. arb->tag = NextChar(h, buf, len);
  82. PORT_Assert(h->state == notDone);
  83. /*
  84. * NOTE: This does not handle the high-tag-number form
  85. */
  86. if ((arb->tag & DER_HIGH_TAG_NUMBER) == DER_HIGH_TAG_NUMBER) {
  87. PORT_SetError(SEC_ERROR_BAD_DER);
  88. h->state = parseError;
  89. return;
  90. }
  91. h->pending = UNKNOWN;
  92. arb->length = UNKNOWN;
  93. if (arb->tag & DER_CONSTRUCTED) {
  94. arb->body.cons.numSubs = 0;
  95. arb->body.cons.subs = NULL;
  96. } else {
  97. arb->body.item.len = UNKNOWN;
  98. arb->body.item.data = NULL;
  99. }
  100. h->state = tagDone;
  101. }
  102. static void ParseLength(BERParse *h, unsigned char **buf, int *len)
  103. {
  104. Byte b;
  105. SECArb *arb = &(h->stackPtr->arb);
  106. PORT_Assert(h->state == notDone);
  107. if (h->pending == UNKNOWN) {
  108. b = NextChar(h, buf, len);
  109. if ((b & 0x80) == 0) { /* short form */
  110. arb->length = b;
  111. /*
  112. * if the tag and the length are both zero bytes, then this
  113. * should be the marker showing end of list for the
  114. * indefinite length composite
  115. */
  116. if (arb->length == 0 && arb->tag == 0)
  117. h->state = compositeDone;
  118. else
  119. h->state = lengthDone;
  120. return;
  121. }
  122. h->pending = b & 0x7f;
  123. /* 0 implies this is an indefinite length */
  124. if (h->pending > 4) {
  125. PORT_SetError(SEC_ERROR_BAD_DER);
  126. h->state = parseError;
  127. return;
  128. }
  129. arb->length = 0;
  130. }
  131. while ((*len > 0) && (h->pending > 0)) {
  132. b = NextChar(h, buf, len);
  133. arb->length = (arb->length << 8) + b;
  134. h->pending--;
  135. }
  136. if (h->pending == 0) {
  137. if (h->derOnly && (arb->length == 0))
  138. h->state = parseError;
  139. else
  140. h->state = lengthDone;
  141. }
  142. return;
  143. }
  144. static void ParseLeaf(BERParse *h, unsigned char **buf, int *len)
  145. {
  146. int count;
  147. SECArb *arb = &(h->stackPtr->arb);
  148. PORT_Assert(h->state == notDone);
  149. PORT_Assert(h->pending >= 0);
  150. if (*len < h->pending)
  151. count = *len;
  152. else
  153. count = h->pending;
  154. if (h->keepLeaves)
  155. memcpy(arb->body.item.data + arb->body.item.len, *buf, count);
  156. if (h->filter)
  157. (*h->filter)(h->filterArg, *buf, count);
  158. *buf += count;
  159. *len -= count;
  160. arb->body.item.len += count;
  161. h->pending -= count;
  162. h->pos += count;
  163. if (h->pending == 0) {
  164. h->state = leafDone;
  165. }
  166. return;
  167. }
  168. static void CreateArbNode(BERParse *h)
  169. {
  170. SECArb *arb = PORT_ArenaAlloc(h->his, sizeof(SECArb));
  171. *arb = h->stackPtr->arb;
  172. /*
  173. * Special case closing the root
  174. */
  175. if (h->stackPtr == h->stack) {
  176. PORT_Assert(arb->tag & DER_CONSTRUCTED);
  177. h->state = parseComplete;
  178. } else {
  179. SECArb *parent = h->stackPtr->parent;
  180. parent->body.cons.subs = DS_ArenaGrow(
  181. h->his, parent->body.cons.subs,
  182. (parent->body.cons.numSubs) * sizeof(SECArb*),
  183. (parent->body.cons.numSubs + 1) * sizeof(SECArb*));
  184. parent->body.cons.subs[parent->body.cons.numSubs] = arb;
  185. parent->body.cons.numSubs++;
  186. h->proc = ParseTag;
  187. h->state = notDone;
  188. h->pending = UNKNOWN;
  189. }
  190. if (h->after)
  191. (*h->after)(h->afterArg, arb, h->stackPtr - h->stack, PR_FALSE);
  192. }
  193. SECStatus BER_ParseSome(BERParse *h, unsigned char *buf, int len)
  194. {
  195. if (h->state == parseError) return PR_TRUE;
  196. while (len) {
  197. (*h->proc)(h, &buf, &len);
  198. if (h->state == parseComplete) {
  199. PORT_SetError(SEC_ERROR_BAD_DER);
  200. h->state = parseError;
  201. return PR_TRUE;
  202. }
  203. if (h->state == parseError) return PR_TRUE;
  204. PORT_Assert(h->state != parseComplete);
  205. if (h->state <= compositeDone) {
  206. if (h->proc == ParseTag) {
  207. PORT_Assert(h->state == tagDone);
  208. h->proc = ParseLength;
  209. h->state = notDone;
  210. } else if (h->proc == ParseLength) {
  211. SECArb *arb = &(h->stackPtr->arb);
  212. PORT_Assert(h->state == lengthDone || h->state == compositeDone);
  213. if (h->before)
  214. (*h->before)(h->beforeArg, arb,
  215. h->stackPtr - h->stack, PR_TRUE);
  216. /*
  217. * Check to see if this is the end of an indefinite
  218. * length composite
  219. */
  220. if (h->state == compositeDone) {
  221. SECArb *parent = h->stackPtr->parent;
  222. PORT_Assert(parent);
  223. PORT_Assert(parent->tag & DER_CONSTRUCTED);
  224. if (parent->length != 0) {
  225. PORT_SetError(SEC_ERROR_BAD_DER);
  226. h->state = parseError;
  227. return PR_TRUE;
  228. }
  229. /*
  230. * NOTE: This does not check for an indefinite length
  231. * composite being contained inside a definite length
  232. * composite. It is not clear that is legal.
  233. */
  234. h->stackPtr--;
  235. CreateArbNode(h);
  236. } else {
  237. h->stackPtr->pos = h->pos;
  238. if (arb->tag & DER_CONSTRUCTED) {
  239. SECArb *parent;
  240. /*
  241. * Make sure there is room on the stack before we
  242. * stick anything else there.
  243. */
  244. PORT_Assert(h->stackPtr - h->stack < h->stackDepth);
  245. if (h->stackPtr - h->stack == h->stackDepth - 1) {
  246. int newDepth = h->stackDepth * 2;
  247. h->stack = DS_ArenaGrow(h->mine, h->stack,
  248. sizeof(ParseStackElem) * h->stackDepth,
  249. sizeof(ParseStackElem) * newDepth);
  250. h->stackPtr = h->stack + h->stackDepth + 1;
  251. h->stackDepth = newDepth;
  252. }
  253. parent = &(h->stackPtr->arb);
  254. h->stackPtr++;
  255. h->stackPtr->parent = parent;
  256. h->proc = ParseTag;
  257. h->state = notDone;
  258. h->pending = UNKNOWN;
  259. } else {
  260. if (arb->length < 0) {
  261. PORT_SetError(SEC_ERROR_BAD_DER);
  262. h->state = parseError;
  263. return PR_TRUE;
  264. }
  265. arb->body.item.len = 0;
  266. if (arb->length > 0 && h->keepLeaves) {
  267. arb->body.item.data =
  268. PORT_ArenaAlloc(h->his, arb->length);
  269. } else {
  270. arb->body.item.data = NULL;
  271. }
  272. h->proc = ParseLeaf;
  273. h->state = notDone;
  274. h->pending = arb->length;
  275. }
  276. }
  277. } else {
  278. ParseStackElem *parent;
  279. PORT_Assert(h->state = leafDone);
  280. PORT_Assert(h->proc == ParseLeaf);
  281. for (;;) {
  282. CreateArbNode(h);
  283. if (h->stackPtr == h->stack)
  284. break;
  285. parent = (h->stackPtr - 1);
  286. PORT_Assert(parent->arb.tag & DER_CONSTRUCTED);
  287. if (parent->arb.length == 0) /* need explicit end */
  288. break;
  289. if (parent->pos + parent->arb.length > h->pos)
  290. break;
  291. if (parent->pos + parent->arb.length < h->pos) {
  292. PORT_SetError(SEC_ERROR_BAD_DER);
  293. h->state = parseError;
  294. return PR_TRUE;
  295. }
  296. h->stackPtr = parent;
  297. }
  298. }
  299. }
  300. }
  301. return PR_FALSE;
  302. }
  303. BERParse *BER_ParseInit(PRArenaPool *arena, PRBool derOnly)
  304. {
  305. BERParse *h;
  306. PRArenaPool *temp = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  307. if (temp == NULL) {
  308. PORT_SetError(SEC_ERROR_NO_MEMORY);
  309. return NULL;
  310. }
  311. h = PORT_ArenaAlloc(temp, sizeof(BERParse));
  312. if (h == NULL) {
  313. PORT_FreeArena(temp, PR_FALSE);
  314. PORT_SetError(SEC_ERROR_NO_MEMORY);
  315. return NULL;
  316. }
  317. h->his = arena;
  318. h->mine = temp;
  319. h->proc = ParseTag;
  320. h->stackDepth = 20;
  321. h->stack = PORT_ArenaZAlloc(h->mine,
  322. sizeof(ParseStackElem) * h->stackDepth);
  323. h->stackPtr = h->stack;
  324. h->state = notDone;
  325. h->pos = 0;
  326. h->keepLeaves = PR_TRUE;
  327. h->before = NULL;
  328. h->after = NULL;
  329. h->filter = NULL;
  330. h->derOnly = derOnly;
  331. return h;
  332. }
  333. SECArb *BER_ParseFini(BERParse *h)
  334. {
  335. PRArenaPool *myArena = h->mine;
  336. SECArb *arb;
  337. if (h->state != parseComplete) {
  338. arb = NULL;
  339. } else {
  340. arb = PORT_ArenaAlloc(h->his, sizeof(SECArb));
  341. *arb = h->stackPtr->arb;
  342. }
  343. PORT_FreeArena(myArena, PR_FALSE);
  344. return arb;
  345. }
  346. void BER_SetFilter(BERParse *h, BERFilterProc proc, void *instance)
  347. {
  348. h->filter = proc;
  349. h->filterArg = instance;
  350. }
  351. void BER_SetLeafStorage(BERParse *h, PRBool keep)
  352. {
  353. h->keepLeaves = keep;
  354. }
  355. void BER_SetNotifyProc(BERParse *h, BERNotifyProc proc, void *instance,
  356. PRBool beforeData)
  357. {
  358. if (beforeData) {
  359. h->before = proc;
  360. h->beforeArg = instance;
  361. } else {
  362. h->after = proc;
  363. h->afterArg = instance;
  364. }
  365. }