/security/nss/lib/util/secasn1e.c

http://github.com/zpao/v8monkey · C · 1647 lines · 1019 code · 241 blank · 387 comment · 271 complexity · e7c275544a4144a0fb14de594c975be8 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. /*
  37. * Support for ENcoding ASN.1 data based on BER/DER (Basic/Distinguished
  38. * Encoding Rules).
  39. *
  40. * $Id: secasn1e.c,v 1.22 2011/01/13 00:23:33 wtc%google.com Exp $
  41. */
  42. #include "secasn1.h"
  43. typedef enum {
  44. beforeHeader,
  45. duringContents,
  46. duringGroup,
  47. duringSequence,
  48. afterContents,
  49. afterImplicit,
  50. afterInline,
  51. afterPointer,
  52. afterChoice,
  53. notInUse
  54. } sec_asn1e_parse_place;
  55. typedef enum {
  56. allDone,
  57. encodeError,
  58. keepGoing,
  59. needBytes
  60. } sec_asn1e_parse_status;
  61. typedef enum {
  62. hdr_normal = 0, /* encode header normally */
  63. hdr_any = 1, /* header already encoded in content */
  64. hdr_decoder = 2, /* template only used by decoder. skip it. */
  65. hdr_optional = 3, /* optional component, to be omitted */
  66. hdr_placeholder = 4 /* place holder for from_buf content */
  67. } sec_asn1e_hdr_encoding;
  68. typedef struct sec_asn1e_state_struct {
  69. SEC_ASN1EncoderContext *top;
  70. const SEC_ASN1Template *theTemplate;
  71. void *src;
  72. struct sec_asn1e_state_struct *parent; /* aka prev */
  73. struct sec_asn1e_state_struct *child; /* aka next */
  74. sec_asn1e_parse_place place; /* where we are in encoding process */
  75. /*
  76. * XXX explain the next fields as clearly as possible...
  77. */
  78. unsigned char tag_modifiers;
  79. unsigned char tag_number;
  80. unsigned long underlying_kind;
  81. int depth;
  82. PRBool isExplicit, /* we are handling an isExplicit header */
  83. indefinite, /* need end-of-contents */
  84. is_string, /* encoding a simple string or an ANY */
  85. may_stream, /* when streaming, do indefinite encoding */
  86. optional, /* omit field if it has no contents */
  87. disallowStreaming; /* disallow streaming in all sub-templates */
  88. } sec_asn1e_state;
  89. /*
  90. * An "outsider" will have an opaque pointer to this, created by calling
  91. * SEC_ASN1EncoderStart(). It will be passed back in to all subsequent
  92. * calls to SEC_ASN1EncoderUpdate() and related routines, and when done
  93. * it is passed to SEC_ASN1EncoderFinish().
  94. */
  95. struct sec_EncoderContext_struct {
  96. PRArenaPool *our_pool; /* for our internal allocs */
  97. sec_asn1e_state *current;
  98. sec_asn1e_parse_status status;
  99. PRBool streaming;
  100. PRBool from_buf;
  101. SEC_ASN1NotifyProc notify_proc; /* call before/after handling field */
  102. void *notify_arg; /* argument to notify_proc */
  103. PRBool during_notify; /* true during call to notify_proc */
  104. SEC_ASN1WriteProc output_proc; /* pass encoded bytes to this */
  105. void *output_arg; /* argument to that function */
  106. };
  107. static sec_asn1e_state *
  108. sec_asn1e_push_state (SEC_ASN1EncoderContext *cx,
  109. const SEC_ASN1Template *theTemplate,
  110. const void *src, PRBool new_depth)
  111. {
  112. sec_asn1e_state *state, *new_state;
  113. state = cx->current;
  114. new_state = (sec_asn1e_state*)PORT_ArenaZAlloc (cx->our_pool,
  115. sizeof(*new_state));
  116. if (new_state == NULL) {
  117. cx->status = encodeError;
  118. return NULL;
  119. }
  120. new_state->top = cx;
  121. new_state->parent = state;
  122. new_state->theTemplate = theTemplate;
  123. new_state->place = notInUse;
  124. if (src != NULL)
  125. new_state->src = (char *)src + theTemplate->offset;
  126. if (state != NULL) {
  127. new_state->depth = state->depth;
  128. if (new_depth)
  129. new_state->depth++;
  130. state->child = new_state;
  131. }
  132. cx->current = new_state;
  133. return new_state;
  134. }
  135. static void
  136. sec_asn1e_scrub_state (sec_asn1e_state *state)
  137. {
  138. /*
  139. * Some default "scrubbing".
  140. * XXX right set of initializations?
  141. */
  142. state->place = beforeHeader;
  143. state->indefinite = PR_FALSE;
  144. }
  145. static void
  146. sec_asn1e_notify_before (SEC_ASN1EncoderContext *cx, void *src, int depth)
  147. {
  148. if (cx->notify_proc == NULL)
  149. return;
  150. cx->during_notify = PR_TRUE;
  151. (* cx->notify_proc) (cx->notify_arg, PR_TRUE, src, depth);
  152. cx->during_notify = PR_FALSE;
  153. }
  154. static void
  155. sec_asn1e_notify_after (SEC_ASN1EncoderContext *cx, void *src, int depth)
  156. {
  157. if (cx->notify_proc == NULL)
  158. return;
  159. cx->during_notify = PR_TRUE;
  160. (* cx->notify_proc) (cx->notify_arg, PR_FALSE, src, depth);
  161. cx->during_notify = PR_FALSE;
  162. }
  163. static sec_asn1e_state *
  164. sec_asn1e_init_state_based_on_template (sec_asn1e_state *state)
  165. {
  166. PRBool isExplicit, is_string, may_stream, optional, universal;
  167. PRBool disallowStreaming;
  168. unsigned char tag_modifiers;
  169. unsigned long encode_kind, under_kind;
  170. unsigned long tag_number;
  171. PRBool isInline = PR_FALSE;
  172. encode_kind = state->theTemplate->kind;
  173. universal = ((encode_kind & SEC_ASN1_CLASS_MASK) == SEC_ASN1_UNIVERSAL)
  174. ? PR_TRUE : PR_FALSE;
  175. isExplicit = (encode_kind & SEC_ASN1_EXPLICIT) ? PR_TRUE : PR_FALSE;
  176. encode_kind &= ~SEC_ASN1_EXPLICIT;
  177. optional = (encode_kind & SEC_ASN1_OPTIONAL) ? PR_TRUE : PR_FALSE;
  178. encode_kind &= ~SEC_ASN1_OPTIONAL;
  179. PORT_Assert (!(isExplicit && universal)); /* bad templates */
  180. may_stream = (encode_kind & SEC_ASN1_MAY_STREAM) ? PR_TRUE : PR_FALSE;
  181. encode_kind &= ~SEC_ASN1_MAY_STREAM;
  182. disallowStreaming = (encode_kind & SEC_ASN1_NO_STREAM) ? PR_TRUE : PR_FALSE;
  183. encode_kind &= ~SEC_ASN1_NO_STREAM;
  184. /* Just clear this to get it out of the way; we do not need it here */
  185. encode_kind &= ~SEC_ASN1_DYNAMIC;
  186. if( encode_kind & SEC_ASN1_CHOICE ) {
  187. under_kind = SEC_ASN1_CHOICE;
  188. } else if ((encode_kind & (SEC_ASN1_POINTER | SEC_ASN1_INLINE)) ||
  189. (!universal && !isExplicit)) {
  190. const SEC_ASN1Template *subt;
  191. void *src = NULL;
  192. PORT_Assert ((encode_kind & (SEC_ASN1_ANY | SEC_ASN1_SKIP)) == 0);
  193. sec_asn1e_scrub_state (state);
  194. if (encode_kind & SEC_ASN1_POINTER) {
  195. src = *(void **)state->src;
  196. state->place = afterPointer;
  197. if (src == NULL) {
  198. /*
  199. * If this is optional, but NULL, then the field does
  200. * not need to be encoded. In this case we are done;
  201. * we do not want to push a subtemplate.
  202. */
  203. if (optional)
  204. return state;
  205. /*
  206. * XXX this is an error; need to figure out
  207. * how to handle this
  208. */
  209. }
  210. } else {
  211. src = state->src;
  212. if (encode_kind & SEC_ASN1_INLINE) {
  213. /* check that there are no extraneous bits */
  214. /* PORT_Assert (encode_kind == SEC_ASN1_INLINE && !optional); */
  215. state->place = afterInline;
  216. isInline = PR_TRUE;
  217. } else {
  218. /*
  219. * Save the tag modifiers and tag number here before moving
  220. * on to the next state in case this is a member of a
  221. * SEQUENCE OF
  222. */
  223. state->tag_modifiers = (unsigned char)
  224. (encode_kind & (SEC_ASN1_TAG_MASK & ~SEC_ASN1_TAGNUM_MASK));
  225. state->tag_number = (unsigned char)
  226. (encode_kind & SEC_ASN1_TAGNUM_MASK);
  227. state->place = afterImplicit;
  228. state->optional = optional;
  229. }
  230. }
  231. subt = SEC_ASN1GetSubtemplate (state->theTemplate, state->src, PR_TRUE);
  232. if (isInline && optional) {
  233. /* we only handle a very limited set of optional inline cases at
  234. this time */
  235. if (PR_FALSE != SEC_ASN1IsTemplateSimple(subt)) {
  236. /* we now know that the target is a SECItem*, so we can check
  237. if the source contains one */
  238. SECItem* target = (SECItem*)state->src;
  239. if (!target || !target->data || !target->len) {
  240. /* no valid data to encode subtemplate */
  241. return state;
  242. }
  243. } else {
  244. PORT_Assert(0); /* complex templates are not handled as
  245. inline optional */
  246. }
  247. }
  248. state = sec_asn1e_push_state (state->top, subt, src, PR_FALSE);
  249. if (state == NULL)
  250. return state;
  251. if (universal) {
  252. /*
  253. * This is a POINTER or INLINE; just init based on that
  254. * and we are done.
  255. */
  256. return sec_asn1e_init_state_based_on_template (state);
  257. }
  258. /*
  259. * This is an implicit, non-universal (meaning, application-private
  260. * or context-specific) field. This results in a "magic" tag but
  261. * encoding based on the underlying type. We pushed a new state
  262. * that is based on the subtemplate (the underlying type), but
  263. * now we will sort of alias it to give it some of our properties
  264. * (tag, optional status, etc.).
  265. *
  266. * NB: ALL the following flags in the subtemplate are disallowed
  267. * and/or ignored: EXPLICIT, OPTIONAL, INNER, INLINE, POINTER.
  268. */
  269. under_kind = state->theTemplate->kind;
  270. if ((under_kind & SEC_ASN1_MAY_STREAM) && !disallowStreaming) {
  271. may_stream = PR_TRUE;
  272. }
  273. under_kind &= ~(SEC_ASN1_MAY_STREAM | SEC_ASN1_DYNAMIC);
  274. } else {
  275. under_kind = encode_kind;
  276. }
  277. /*
  278. * Sanity check that there are no unwanted bits marked in under_kind.
  279. * These bits were either removed above (after we recorded them) or
  280. * they simply should not be found (signalling a bad/broken template).
  281. * XXX is this the right set of bits to test here? (i.e. need to add
  282. * or remove any?)
  283. */
  284. #define UNEXPECTED_FLAGS \
  285. (SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_SKIP | SEC_ASN1_INNER | \
  286. SEC_ASN1_DYNAMIC | SEC_ASN1_MAY_STREAM | SEC_ASN1_INLINE | SEC_ASN1_POINTER)
  287. PORT_Assert ((under_kind & UNEXPECTED_FLAGS) == 0);
  288. under_kind &= ~UNEXPECTED_FLAGS;
  289. #undef UNEXPECTED_FLAGS
  290. if (encode_kind & SEC_ASN1_ANY) {
  291. PORT_Assert (encode_kind == under_kind);
  292. tag_modifiers = 0;
  293. tag_number = 0;
  294. is_string = PR_TRUE;
  295. } else {
  296. tag_modifiers = (unsigned char)
  297. (encode_kind & (SEC_ASN1_TAG_MASK & ~SEC_ASN1_TAGNUM_MASK));
  298. /*
  299. * XXX This assumes only single-octet identifiers. To handle
  300. * the HIGH TAG form we would need to do some more work, especially
  301. * in how to specify them in the template, because right now we
  302. * do not provide a way to specify more *tag* bits in encode_kind.
  303. */
  304. tag_number = encode_kind & SEC_ASN1_TAGNUM_MASK;
  305. is_string = PR_FALSE;
  306. switch (under_kind & SEC_ASN1_TAGNUM_MASK) {
  307. case SEC_ASN1_SET:
  308. /*
  309. * XXX A plain old SET (as opposed to a SET OF) is not implemented.
  310. * If it ever is, remove this assert...
  311. */
  312. PORT_Assert ((under_kind & SEC_ASN1_GROUP) != 0);
  313. /* fallthru */
  314. case SEC_ASN1_SEQUENCE:
  315. tag_modifiers |= SEC_ASN1_CONSTRUCTED;
  316. break;
  317. case SEC_ASN1_BIT_STRING:
  318. case SEC_ASN1_BMP_STRING:
  319. case SEC_ASN1_GENERALIZED_TIME:
  320. case SEC_ASN1_IA5_STRING:
  321. case SEC_ASN1_OCTET_STRING:
  322. case SEC_ASN1_PRINTABLE_STRING:
  323. case SEC_ASN1_T61_STRING:
  324. case SEC_ASN1_UNIVERSAL_STRING:
  325. case SEC_ASN1_UTC_TIME:
  326. case SEC_ASN1_UTF8_STRING:
  327. case SEC_ASN1_VISIBLE_STRING:
  328. /*
  329. * We do not yet know if we will be constructing the string,
  330. * so we have to wait to do this final tag modification.
  331. */
  332. is_string = PR_TRUE;
  333. break;
  334. }
  335. }
  336. state->tag_modifiers = tag_modifiers;
  337. state->tag_number = (unsigned char)tag_number;
  338. state->underlying_kind = under_kind;
  339. state->isExplicit = isExplicit;
  340. state->may_stream = may_stream;
  341. state->is_string = is_string;
  342. state->optional = optional;
  343. state->disallowStreaming = disallowStreaming;
  344. sec_asn1e_scrub_state (state);
  345. return state;
  346. }
  347. static void
  348. sec_asn1e_write_part (sec_asn1e_state *state,
  349. const char *buf, unsigned long len,
  350. SEC_ASN1EncodingPart part)
  351. {
  352. SEC_ASN1EncoderContext *cx;
  353. cx = state->top;
  354. (* cx->output_proc) (cx->output_arg, buf, len, state->depth, part);
  355. }
  356. /*
  357. * XXX This assumes only single-octet identifiers. To handle
  358. * the HIGH TAG form we would need to modify this interface and
  359. * teach it to properly encode the special form.
  360. */
  361. static void
  362. sec_asn1e_write_identifier_bytes (sec_asn1e_state *state, unsigned char value)
  363. {
  364. char byte;
  365. byte = (char) value;
  366. sec_asn1e_write_part (state, &byte, 1, SEC_ASN1_Identifier);
  367. }
  368. int
  369. SEC_ASN1EncodeLength(unsigned char *buf,int value) {
  370. int lenlen;
  371. lenlen = SEC_ASN1LengthLength (value);
  372. if (lenlen == 1) {
  373. buf[0] = value;
  374. } else {
  375. int i;
  376. i = lenlen - 1;
  377. buf[0] = 0x80 | i;
  378. while (i) {
  379. buf[i--] = value;
  380. value >>= 8;
  381. }
  382. PORT_Assert (value == 0);
  383. }
  384. return lenlen;
  385. }
  386. static void
  387. sec_asn1e_write_length_bytes (sec_asn1e_state *state, unsigned long value,
  388. PRBool indefinite)
  389. {
  390. int lenlen;
  391. unsigned char buf[sizeof(unsigned long) + 1];
  392. if (indefinite) {
  393. PORT_Assert (value == 0);
  394. buf[0] = 0x80;
  395. lenlen = 1;
  396. } else {
  397. lenlen = SEC_ASN1EncodeLength(buf,value);
  398. }
  399. sec_asn1e_write_part (state, (char *) buf, lenlen, SEC_ASN1_Length);
  400. }
  401. static void
  402. sec_asn1e_write_contents_bytes (sec_asn1e_state *state,
  403. const char *buf, unsigned long len)
  404. {
  405. sec_asn1e_write_part (state, buf, len, SEC_ASN1_Contents);
  406. }
  407. static void
  408. sec_asn1e_write_end_of_contents_bytes (sec_asn1e_state *state)
  409. {
  410. const char eoc[2] = {0, 0};
  411. sec_asn1e_write_part (state, eoc, 2, SEC_ASN1_EndOfContents);
  412. }
  413. static int
  414. sec_asn1e_which_choice
  415. (
  416. void *src,
  417. const SEC_ASN1Template *theTemplate
  418. )
  419. {
  420. int rv;
  421. unsigned int which = *(unsigned int *)src;
  422. for( rv = 1, theTemplate++; theTemplate->kind != 0; rv++, theTemplate++ ) {
  423. if( which == theTemplate->size ) {
  424. return rv;
  425. }
  426. }
  427. return 0;
  428. }
  429. static unsigned long
  430. sec_asn1e_contents_length (const SEC_ASN1Template *theTemplate, void *src,
  431. PRBool disallowStreaming, PRBool insideIndefinite,
  432. sec_asn1e_hdr_encoding *pHdrException)
  433. {
  434. unsigned long encode_kind, underlying_kind;
  435. PRBool isExplicit, optional, universal, may_stream;
  436. unsigned long len;
  437. /*
  438. * This function currently calculates the length in all cases
  439. * except the following: when writing out the contents of a
  440. * template that belongs to a state where it was a sub-template
  441. * with the SEC_ASN1_MAY_STREAM bit set and it's parent had the
  442. * optional bit set. The information that the parent is optional
  443. * and that we should return the length of 0 when that length is
  444. * present since that means the optional field is no longer present.
  445. * So we add the disallowStreaming flag which is passed in when
  446. * writing the contents, but for all recursive calls to
  447. * sec_asn1e_contents_length, we pass PR_FALSE, because this
  448. * function correctly calculates the length for children templates
  449. * from that point on. Confused yet? At least you didn't have
  450. * to figure it out. ;) -javi
  451. */
  452. encode_kind = theTemplate->kind;
  453. universal = ((encode_kind & SEC_ASN1_CLASS_MASK) == SEC_ASN1_UNIVERSAL)
  454. ? PR_TRUE : PR_FALSE;
  455. isExplicit = (encode_kind & SEC_ASN1_EXPLICIT) ? PR_TRUE : PR_FALSE;
  456. encode_kind &= ~SEC_ASN1_EXPLICIT;
  457. optional = (encode_kind & SEC_ASN1_OPTIONAL) ? PR_TRUE : PR_FALSE;
  458. encode_kind &= ~SEC_ASN1_OPTIONAL;
  459. PORT_Assert (!(isExplicit && universal)); /* bad templates */
  460. may_stream = (encode_kind & SEC_ASN1_MAY_STREAM) ? PR_TRUE : PR_FALSE;
  461. encode_kind &= ~SEC_ASN1_MAY_STREAM;
  462. /* Just clear this to get it out of the way; we do not need it here */
  463. encode_kind &= ~SEC_ASN1_DYNAMIC;
  464. if (encode_kind & SEC_ASN1_NO_STREAM) {
  465. disallowStreaming = PR_TRUE;
  466. }
  467. encode_kind &= ~SEC_ASN1_NO_STREAM;
  468. if (encode_kind & SEC_ASN1_CHOICE) {
  469. void *src2;
  470. int indx = sec_asn1e_which_choice(src, theTemplate);
  471. if (0 == indx) {
  472. /* XXX set an error? "choice not found" */
  473. /* state->top->status = encodeError; */
  474. return 0;
  475. }
  476. src2 = (void *)
  477. ((char *)src - theTemplate->offset + theTemplate[indx].offset);
  478. return sec_asn1e_contents_length(&theTemplate[indx], src2,
  479. disallowStreaming, insideIndefinite,
  480. pHdrException);
  481. }
  482. if ((encode_kind & (SEC_ASN1_POINTER | SEC_ASN1_INLINE)) || !universal) {
  483. /* XXX any bits we want to disallow (PORT_Assert against) here? */
  484. theTemplate = SEC_ASN1GetSubtemplate (theTemplate, src, PR_TRUE);
  485. if (encode_kind & SEC_ASN1_POINTER) {
  486. src = *(void **)src;
  487. if (src == NULL) {
  488. *pHdrException = optional ? hdr_optional : hdr_normal;
  489. return 0;
  490. }
  491. } else if (encode_kind & SEC_ASN1_INLINE) {
  492. /* check that there are no extraneous bits */
  493. if (optional) {
  494. if (PR_FALSE != SEC_ASN1IsTemplateSimple(theTemplate)) {
  495. /* we now know that the target is a SECItem*, so we can check
  496. if the source contains one */
  497. SECItem* target = (SECItem*)src;
  498. if (!target || !target->data || !target->len) {
  499. /* no valid data to encode subtemplate */
  500. *pHdrException = hdr_optional;
  501. return 0;
  502. }
  503. } else {
  504. PORT_Assert(0); /* complex templates not handled as inline
  505. optional */
  506. }
  507. }
  508. }
  509. src = (char *)src + theTemplate->offset;
  510. /* recurse to find the length of the subtemplate */
  511. len = sec_asn1e_contents_length (theTemplate, src, disallowStreaming,
  512. insideIndefinite, pHdrException);
  513. if (len == 0 && optional) {
  514. *pHdrException = hdr_optional;
  515. } else if (isExplicit) {
  516. if (*pHdrException == hdr_any) {
  517. /* *we* do not want to add in a header,
  518. ** but our caller still does.
  519. */
  520. *pHdrException = hdr_normal;
  521. } else if (*pHdrException == hdr_normal) {
  522. /* if the inner content exists, our length is
  523. * len(identifier) + len(length) + len(innercontent)
  524. * XXX we currently assume len(identifier) == 1;
  525. * to support a high-tag-number this would need to be smarter.
  526. */
  527. len += 1 + SEC_ASN1LengthLength (len);
  528. }
  529. }
  530. return len;
  531. }
  532. underlying_kind = encode_kind;
  533. /* This is only used in decoding; it plays no part in encoding. */
  534. if (underlying_kind & SEC_ASN1_SAVE) {
  535. /* check that there are no extraneous bits */
  536. PORT_Assert (underlying_kind == SEC_ASN1_SAVE);
  537. *pHdrException = hdr_decoder;
  538. return 0;
  539. }
  540. #define UNEXPECTED_FLAGS \
  541. (SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_INLINE | SEC_ASN1_POINTER |\
  542. SEC_ASN1_DYNAMIC | SEC_ASN1_MAY_STREAM | SEC_ASN1_SAVE | SEC_ASN1_SKIP)
  543. /* Having any of these bits is not expected here... */
  544. PORT_Assert ((underlying_kind & UNEXPECTED_FLAGS) == 0);
  545. underlying_kind &= ~UNEXPECTED_FLAGS;
  546. #undef UNEXPECTED_FLAGS
  547. if (underlying_kind & SEC_ASN1_CHOICE) {
  548. void *src2;
  549. int indx = sec_asn1e_which_choice(src, theTemplate);
  550. if (0 == indx) {
  551. /* XXX set an error? "choice not found" */
  552. /* state->top->status = encodeError; */
  553. return 0;
  554. }
  555. src2 = (void *)
  556. ((char *)src - theTemplate->offset + theTemplate[indx].offset);
  557. len = sec_asn1e_contents_length(&theTemplate[indx], src2,
  558. disallowStreaming, insideIndefinite,
  559. pHdrException);
  560. } else {
  561. switch (underlying_kind) {
  562. case SEC_ASN1_SEQUENCE_OF:
  563. case SEC_ASN1_SET_OF:
  564. {
  565. const SEC_ASN1Template *tmpt;
  566. void *sub_src;
  567. unsigned long sub_len;
  568. void **group;
  569. len = 0;
  570. group = *(void ***)src;
  571. if (group == NULL)
  572. break;
  573. tmpt = SEC_ASN1GetSubtemplate (theTemplate, src, PR_TRUE);
  574. for (; *group != NULL; group++) {
  575. sub_src = (char *)(*group) + tmpt->offset;
  576. sub_len = sec_asn1e_contents_length (tmpt, sub_src,
  577. disallowStreaming,
  578. insideIndefinite,
  579. pHdrException);
  580. len += sub_len;
  581. /*
  582. * XXX The 1 below is the presumed length of the identifier;
  583. * to support a high-tag-number this would need to be smarter.
  584. */
  585. if (*pHdrException == hdr_normal)
  586. len += 1 + SEC_ASN1LengthLength (sub_len);
  587. }
  588. }
  589. break;
  590. case SEC_ASN1_SEQUENCE:
  591. case SEC_ASN1_SET:
  592. {
  593. const SEC_ASN1Template *tmpt;
  594. void *sub_src;
  595. unsigned long sub_len;
  596. len = 0;
  597. for (tmpt = theTemplate + 1; tmpt->kind; tmpt++) {
  598. sub_src = (char *)src + tmpt->offset;
  599. sub_len = sec_asn1e_contents_length (tmpt, sub_src,
  600. disallowStreaming,
  601. insideIndefinite,
  602. pHdrException);
  603. len += sub_len;
  604. /*
  605. * XXX The 1 below is the presumed length of the identifier;
  606. * to support a high-tag-number this would need to be smarter.
  607. */
  608. if (*pHdrException == hdr_normal)
  609. len += 1 + SEC_ASN1LengthLength (sub_len);
  610. }
  611. }
  612. break;
  613. case SEC_ASN1_BIT_STRING:
  614. /* convert bit length to byte */
  615. len = (((SECItem *)src)->len + 7) >> 3;
  616. /* bit string contents involve an extra octet */
  617. if (len)
  618. len++;
  619. break;
  620. case SEC_ASN1_INTEGER:
  621. /* ASN.1 INTEGERs are signed.
  622. * If the source is an unsigned integer, the encoder will need
  623. * to handle the conversion here.
  624. */
  625. {
  626. unsigned char *buf = ((SECItem *)src)->data;
  627. SECItemType integerType = ((SECItem *)src)->type;
  628. len = ((SECItem *)src)->len;
  629. while (len > 0) {
  630. if (*buf != 0) {
  631. if (*buf & 0x80 && integerType == siUnsignedInteger) {
  632. len++; /* leading zero needed to make number signed */
  633. }
  634. break; /* reached beginning of number */
  635. }
  636. if (len == 1) {
  637. break; /* the number 0 */
  638. }
  639. if (buf[1] & 0x80) {
  640. break; /* leading zero already present */
  641. }
  642. /* extraneous leading zero, keep going */
  643. buf++;
  644. len--;
  645. }
  646. }
  647. break;
  648. default:
  649. len = ((SECItem *)src)->len;
  650. break;
  651. } /* end switch */
  652. #ifndef WHAT_PROBLEM_DOES_THIS_SOLVE
  653. /* if we're streaming, we may have a secitem w/len 0 as placeholder */
  654. if (!len && insideIndefinite && may_stream && !disallowStreaming) {
  655. len = 1;
  656. }
  657. #endif
  658. } /* end else */
  659. if (len == 0 && optional)
  660. *pHdrException = hdr_optional;
  661. else if (underlying_kind == SEC_ASN1_ANY)
  662. *pHdrException = hdr_any;
  663. else
  664. *pHdrException = hdr_normal;
  665. return len;
  666. }
  667. static void
  668. sec_asn1e_write_header (sec_asn1e_state *state)
  669. {
  670. unsigned long contents_length;
  671. unsigned char tag_number, tag_modifiers;
  672. sec_asn1e_hdr_encoding hdrException = hdr_normal;
  673. PRBool indefinite = PR_FALSE;
  674. PORT_Assert (state->place == beforeHeader);
  675. tag_number = state->tag_number;
  676. tag_modifiers = state->tag_modifiers;
  677. if (state->underlying_kind == SEC_ASN1_ANY) {
  678. state->place = duringContents;
  679. return;
  680. }
  681. if (state->underlying_kind & SEC_ASN1_CHOICE) {
  682. int indx = sec_asn1e_which_choice(state->src, state->theTemplate);
  683. if( 0 == indx ) {
  684. /* XXX set an error? "choice not found" */
  685. state->top->status = encodeError;
  686. return;
  687. }
  688. state->place = afterChoice;
  689. state = sec_asn1e_push_state(state->top, &state->theTemplate[indx],
  690. (char *)state->src - state->theTemplate->offset,
  691. PR_TRUE);
  692. if (state) {
  693. /*
  694. * Do the "before" field notification.
  695. */
  696. sec_asn1e_notify_before (state->top, state->src, state->depth);
  697. state = sec_asn1e_init_state_based_on_template (state);
  698. }
  699. return;
  700. }
  701. /* The !isString test below is apparently intended to ensure that all
  702. ** constructed types receive indefinite length encoding.
  703. */
  704. indefinite = (PRBool)
  705. (state->top->streaming && state->may_stream &&
  706. (state->top->from_buf || !state->is_string));
  707. /*
  708. * If we are doing a definite-length encoding, first we have to
  709. * walk the data structure to calculate the entire contents length.
  710. * If we are doing an indefinite-length encoding, we still need to
  711. * know if the contents is:
  712. * optional and to be omitted, or
  713. * an ANY (header is pre-encoded), or
  714. * a SAVE or some other kind of template used only by the decoder.
  715. * So, we call this function either way.
  716. */
  717. contents_length = sec_asn1e_contents_length (state->theTemplate,
  718. state->src,
  719. state->disallowStreaming,
  720. indefinite,
  721. &hdrException);
  722. /*
  723. * We might be told explicitly not to put out a header.
  724. * But it can also be the case, via a pushed subtemplate, that
  725. * sec_asn1e_contents_length could not know that this field is
  726. * really optional. So check for that explicitly, too.
  727. */
  728. if (hdrException != hdr_normal ||
  729. (contents_length == 0 && state->optional)) {
  730. state->place = afterContents;
  731. if (state->top->streaming &&
  732. state->may_stream &&
  733. state->top->from_buf) {
  734. /* we did not find an optional indefinite string, so we
  735. * don't encode it. However, if TakeFromBuf is on, we stop
  736. * here anyway to give our caller a chance to intercept at the
  737. * same point where we would stop if the field were present.
  738. */
  739. state->top->status = needBytes;
  740. }
  741. return;
  742. }
  743. if (indefinite) {
  744. /*
  745. * We need to put out an indefinite-length encoding.
  746. * The only universal types that can be constructed are SETs,
  747. * SEQUENCEs, and strings; so check that it is one of those,
  748. * or that it is not universal (e.g. context-specific).
  749. */
  750. state->indefinite = PR_TRUE;
  751. PORT_Assert ((tag_number == SEC_ASN1_SET)
  752. || (tag_number == SEC_ASN1_SEQUENCE)
  753. || ((tag_modifiers & SEC_ASN1_CLASS_MASK) != 0)
  754. || state->is_string);
  755. tag_modifiers |= SEC_ASN1_CONSTRUCTED;
  756. contents_length = 0;
  757. }
  758. sec_asn1e_write_identifier_bytes (state,
  759. (unsigned char)(tag_number | tag_modifiers));
  760. sec_asn1e_write_length_bytes (state, contents_length, state->indefinite);
  761. if (contents_length == 0 && !state->indefinite) {
  762. /*
  763. * If no real contents to encode, then we are done with this field.
  764. */
  765. state->place = afterContents;
  766. return;
  767. }
  768. /*
  769. * An EXPLICIT is nothing but an outer header, which we have already
  770. * written. Now we need to do the inner header and contents.
  771. */
  772. if (state->isExplicit) {
  773. const SEC_ASN1Template *subt =
  774. SEC_ASN1GetSubtemplate(state->theTemplate, state->src, PR_TRUE);
  775. state->place = afterContents;
  776. state = sec_asn1e_push_state (state->top, subt, state->src, PR_TRUE);
  777. if (state != NULL)
  778. state = sec_asn1e_init_state_based_on_template (state);
  779. return;
  780. }
  781. switch (state->underlying_kind) {
  782. case SEC_ASN1_SET_OF:
  783. case SEC_ASN1_SEQUENCE_OF:
  784. /*
  785. * We need to push a child to handle each member.
  786. */
  787. {
  788. void **group;
  789. const SEC_ASN1Template *subt;
  790. group = *(void ***)state->src;
  791. if (group == NULL || *group == NULL) {
  792. /*
  793. * Group is empty; we are done.
  794. */
  795. state->place = afterContents;
  796. return;
  797. }
  798. state->place = duringGroup;
  799. subt = SEC_ASN1GetSubtemplate (state->theTemplate, state->src,
  800. PR_TRUE);
  801. state = sec_asn1e_push_state (state->top, subt, *group, PR_TRUE);
  802. if (state != NULL)
  803. state = sec_asn1e_init_state_based_on_template (state);
  804. }
  805. break;
  806. case SEC_ASN1_SEQUENCE:
  807. case SEC_ASN1_SET:
  808. /*
  809. * We need to push a child to handle the individual fields.
  810. */
  811. state->place = duringSequence;
  812. state = sec_asn1e_push_state (state->top, state->theTemplate + 1,
  813. state->src, PR_TRUE);
  814. if (state != NULL) {
  815. /*
  816. * Do the "before" field notification.
  817. */
  818. sec_asn1e_notify_before (state->top, state->src, state->depth);
  819. state = sec_asn1e_init_state_based_on_template (state);
  820. }
  821. break;
  822. default:
  823. /*
  824. * I think we do not need to do anything else.
  825. * XXX Correct?
  826. */
  827. state->place = duringContents;
  828. break;
  829. }
  830. }
  831. static void
  832. sec_asn1e_write_contents_from_buf (sec_asn1e_state *state,
  833. const char *buf, unsigned long len)
  834. {
  835. PORT_Assert (state->place == duringContents);
  836. PORT_Assert (state->top->from_buf);
  837. PORT_Assert (state->may_stream && !state->disallowStreaming);
  838. /*
  839. * Probably they just turned on "take from buf", but have not
  840. * yet given us any bytes. If there is nothing in the buffer
  841. * then we have nothing to do but return and wait.
  842. */
  843. if (buf == NULL || len == 0) {
  844. state->top->status = needBytes;
  845. return;
  846. }
  847. /*
  848. * We are streaming, reading from a passed-in buffer.
  849. * This means we are encoding a simple string or an ANY.
  850. * For the former, we need to put out a substring, with its
  851. * own identifier and length. For an ANY, we just write it
  852. * out as is (our caller is required to ensure that it
  853. * is a properly encoded entity).
  854. */
  855. PORT_Assert (state->is_string); /* includes ANY */
  856. if (state->underlying_kind != SEC_ASN1_ANY) {
  857. unsigned char identifier;
  858. /*
  859. * Create the identifier based on underlying_kind. We cannot
  860. * use tag_number and tag_modifiers because this can be an
  861. * implicitly encoded field. In that case, the underlying
  862. * substrings *are* encoded with their real tag.
  863. */
  864. identifier = (unsigned char)
  865. (state->underlying_kind & SEC_ASN1_TAG_MASK);
  866. /*
  867. * The underlying kind should just be a simple string; there
  868. * should be no bits like CONTEXT_SPECIFIC or CONSTRUCTED set.
  869. */
  870. PORT_Assert ((identifier & SEC_ASN1_TAGNUM_MASK) == identifier);
  871. /*
  872. * Write out the tag and length for the substring.
  873. */
  874. sec_asn1e_write_identifier_bytes (state, identifier);
  875. if (state->underlying_kind == SEC_ASN1_BIT_STRING) {
  876. char byte;
  877. /*
  878. * Assume we have a length in bytes but we need to output
  879. * a proper bit string. This interface only works for bit
  880. * strings that are full multiples of 8. If support for
  881. * real, variable length bit strings is needed then the
  882. * caller will have to know to pass in a bit length instead
  883. * of a byte length and then this code will have to
  884. * perform the encoding necessary (length written is length
  885. * in bytes plus 1, and the first octet of string is the
  886. * number of bits remaining between the end of the bit
  887. * string and the next byte boundary).
  888. */
  889. sec_asn1e_write_length_bytes (state, len + 1, PR_FALSE);
  890. byte = 0;
  891. sec_asn1e_write_contents_bytes (state, &byte, 1);
  892. } else {
  893. sec_asn1e_write_length_bytes (state, len, PR_FALSE);
  894. }
  895. }
  896. sec_asn1e_write_contents_bytes (state, buf, len);
  897. state->top->status = needBytes;
  898. }
  899. static void
  900. sec_asn1e_write_contents (sec_asn1e_state *state)
  901. {
  902. unsigned long len = 0;
  903. PORT_Assert (state->place == duringContents);
  904. switch (state->underlying_kind) {
  905. case SEC_ASN1_SET:
  906. case SEC_ASN1_SEQUENCE:
  907. PORT_Assert (0);
  908. break;
  909. case SEC_ASN1_BIT_STRING:
  910. {
  911. SECItem *item;
  912. char rem;
  913. item = (SECItem *)state->src;
  914. len = (item->len + 7) >> 3;
  915. rem = (unsigned char)((len << 3) - item->len); /* remaining bits */
  916. sec_asn1e_write_contents_bytes (state, &rem, 1);
  917. sec_asn1e_write_contents_bytes (state, (char *) item->data, len);
  918. }
  919. break;
  920. case SEC_ASN1_BMP_STRING:
  921. /* The number of bytes must be divisable by 2 */
  922. if ((((SECItem *)state->src)->len) % 2) {
  923. SEC_ASN1EncoderContext *cx;
  924. cx = state->top;
  925. cx->status = encodeError;
  926. break;
  927. }
  928. /* otherwise, fall through to write the content */
  929. goto process_string;
  930. case SEC_ASN1_UNIVERSAL_STRING:
  931. /* The number of bytes must be divisable by 4 */
  932. if ((((SECItem *)state->src)->len) % 4) {
  933. SEC_ASN1EncoderContext *cx;
  934. cx = state->top;
  935. cx->status = encodeError;
  936. break;
  937. }
  938. /* otherwise, fall through to write the content */
  939. goto process_string;
  940. case SEC_ASN1_INTEGER:
  941. /* ASN.1 INTEGERs are signed. If the source is an unsigned
  942. * integer, the encoder will need to handle the conversion here.
  943. */
  944. {
  945. unsigned int blen;
  946. unsigned char *buf;
  947. SECItemType integerType;
  948. blen = ((SECItem *)state->src)->len;
  949. buf = ((SECItem *)state->src)->data;
  950. integerType = ((SECItem *)state->src)->type;
  951. while (blen > 0) {
  952. if (*buf & 0x80 && integerType == siUnsignedInteger) {
  953. char zero = 0; /* write a leading 0 */
  954. sec_asn1e_write_contents_bytes(state, &zero, 1);
  955. /* and then the remaining buffer */
  956. sec_asn1e_write_contents_bytes(state,
  957. (char *)buf, blen);
  958. break;
  959. }
  960. /* Check three possibilities:
  961. * 1. No leading zeros, msb of MSB is not 1;
  962. * 2. The number is zero itself;
  963. * 3. Encoding a signed integer with a leading zero,
  964. * keep the zero so that the number is positive.
  965. */
  966. if (*buf != 0 ||
  967. blen == 1 ||
  968. (buf[1] & 0x80 && integerType != siUnsignedInteger) )
  969. {
  970. sec_asn1e_write_contents_bytes(state,
  971. (char *)buf, blen);
  972. break;
  973. }
  974. /* byte is 0, continue */
  975. buf++;
  976. blen--;
  977. }
  978. }
  979. /* done with this content */
  980. break;
  981. process_string:
  982. default:
  983. {
  984. SECItem *item;
  985. item = (SECItem *)state->src;
  986. sec_asn1e_write_contents_bytes (state, (char *) item->data,
  987. item->len);
  988. }
  989. break;
  990. }
  991. state->place = afterContents;
  992. }
  993. /*
  994. * We are doing a SET OF or SEQUENCE OF, and have just finished an item.
  995. */
  996. static void
  997. sec_asn1e_next_in_group (sec_asn1e_state *state)
  998. {
  999. sec_asn1e_state *child;
  1000. void **group;
  1001. void *member;
  1002. PORT_Assert (state->place == duringGroup);
  1003. PORT_Assert (state->child != NULL);
  1004. child = state->child;
  1005. group = *(void ***)state->src;
  1006. /*
  1007. * Find placement of current item.
  1008. */
  1009. member = (char *)(state->child->src) - child->theTemplate->offset;
  1010. while (*group != member)
  1011. group++;
  1012. /*
  1013. * Move forward to next item.
  1014. */
  1015. group++;
  1016. if (*group == NULL) {
  1017. /*
  1018. * That was our last one; we are done now.
  1019. */
  1020. child->place = notInUse;
  1021. state->place = afterContents;
  1022. return;
  1023. }
  1024. child->src = (char *)(*group) + child->theTemplate->offset;
  1025. /*
  1026. * Re-"push" child.
  1027. */
  1028. sec_asn1e_scrub_state (child);
  1029. state->top->current = child;
  1030. }
  1031. /*
  1032. * We are moving along through a sequence; move forward by one,
  1033. * (detecting end-of-sequence when it happens).
  1034. */
  1035. static void
  1036. sec_asn1e_next_in_sequence (sec_asn1e_state *state)
  1037. {
  1038. sec_asn1e_state *child;
  1039. PORT_Assert (state->place == duringSequence);
  1040. PORT_Assert (state->child != NULL);
  1041. child = state->child;
  1042. /*
  1043. * Do the "after" field notification.
  1044. */
  1045. sec_asn1e_notify_after (state->top, child->src, child->depth);
  1046. /*
  1047. * Move forward.
  1048. */
  1049. child->theTemplate++;
  1050. if (child->theTemplate->kind == 0) {
  1051. /*
  1052. * We are done with this sequence.
  1053. */
  1054. child->place = notInUse;
  1055. state->place = afterContents;
  1056. return;
  1057. }
  1058. /*
  1059. * Reset state and push.
  1060. */
  1061. child->src = (char *)state->src + child->theTemplate->offset;
  1062. /*
  1063. * Do the "before" field notification.
  1064. */
  1065. sec_asn1e_notify_before (state->top, child->src, child->depth);
  1066. state->top->current = child;
  1067. (void) sec_asn1e_init_state_based_on_template (child);
  1068. }
  1069. static void
  1070. sec_asn1e_after_contents (sec_asn1e_state *state)
  1071. {
  1072. PORT_Assert (state->place == afterContents);
  1073. if (state->indefinite)
  1074. sec_asn1e_write_end_of_contents_bytes (state);
  1075. /*
  1076. * Just make my parent be the current state. It will then clean
  1077. * up after me and free me (or reuse me).
  1078. */
  1079. state->top->current = state->parent;
  1080. }
  1081. /*
  1082. * This function is called whether or not we are streaming; if we
  1083. * *are* streaming, our caller can also instruct us to take bytes
  1084. * from the passed-in buffer (at buf, for length len, which is likely
  1085. * bytes but could even mean bits if the current field is a bit string).
  1086. * If we have been so instructed, we will gobble up bytes from there
  1087. * (rather than from our src structure) and output them, and then
  1088. * we will just return, expecting to be called again -- either with
  1089. * more bytes or after our caller has instructed us that we are done
  1090. * (for now) with the buffer.
  1091. */
  1092. SECStatus
  1093. SEC_ASN1EncoderUpdate (SEC_ASN1EncoderContext *cx,
  1094. const char *buf, unsigned long len)
  1095. {
  1096. sec_asn1e_state *state;
  1097. if (cx->status == needBytes) {
  1098. cx->status = keepGoing;
  1099. }
  1100. while (cx->status == keepGoing) {
  1101. state = cx->current;
  1102. switch (state->place) {
  1103. case beforeHeader:
  1104. sec_asn1e_write_header (state);
  1105. break;
  1106. case duringContents:
  1107. if (cx->from_buf)
  1108. sec_asn1e_write_contents_from_buf (state, buf, len);
  1109. else
  1110. sec_asn1e_write_contents (state);
  1111. break;
  1112. case duringGroup:
  1113. sec_asn1e_next_in_group (state);
  1114. break;
  1115. case duringSequence:
  1116. sec_asn1e_next_in_sequence (state);
  1117. break;
  1118. case afterContents:
  1119. sec_asn1e_after_contents (state);
  1120. break;
  1121. case afterImplicit:
  1122. case afterInline:
  1123. case afterPointer:
  1124. case afterChoice:
  1125. /*
  1126. * These states are more documentation than anything.
  1127. * They just need to force a pop.
  1128. */
  1129. PORT_Assert (!state->indefinite);
  1130. state->place = afterContents;
  1131. break;
  1132. case notInUse:
  1133. default:
  1134. /* This is not an error, but rather a plain old BUG! */
  1135. PORT_Assert (0);
  1136. cx->status = encodeError;
  1137. break;
  1138. }
  1139. if (cx->status == encodeError)
  1140. break;
  1141. /* It might have changed, so we have to update our local copy. */
  1142. state = cx->current;
  1143. /* If it is NULL, we have popped all the way to the top. */
  1144. if (state == NULL) {
  1145. cx->status = allDone;
  1146. break;
  1147. }
  1148. }
  1149. if (cx->status == encodeError) {
  1150. return SECFailure;
  1151. }
  1152. return SECSuccess;
  1153. }
  1154. void
  1155. SEC_ASN1EncoderFinish (SEC_ASN1EncoderContext *cx)
  1156. {
  1157. /*
  1158. * XXX anything else that needs to be finished?
  1159. */
  1160. PORT_FreeArena (cx->our_pool, PR_FALSE);
  1161. }
  1162. SEC_ASN1EncoderContext *
  1163. SEC_ASN1EncoderStart (const void *src, const SEC_ASN1Template *theTemplate,
  1164. SEC_ASN1WriteProc output_proc, void *output_arg)
  1165. {
  1166. PRArenaPool *our_pool;
  1167. SEC_ASN1EncoderContext *cx;
  1168. our_pool = PORT_NewArena (SEC_ASN1_DEFAULT_ARENA_SIZE);
  1169. if (our_pool == NULL)
  1170. return NULL;
  1171. cx = (SEC_ASN1EncoderContext*)PORT_ArenaZAlloc (our_pool, sizeof(*cx));
  1172. if (cx == NULL) {
  1173. PORT_FreeArena (our_pool, PR_FALSE);
  1174. return NULL;
  1175. }
  1176. cx->our_pool = our_pool;
  1177. cx->output_proc = output_proc;
  1178. cx->output_arg = output_arg;
  1179. cx->status = keepGoing;
  1180. if (sec_asn1e_push_state(cx, theTemplate, src, PR_FALSE) == NULL
  1181. || sec_asn1e_init_state_based_on_template (cx->current) == NULL) {
  1182. /*
  1183. * Trouble initializing (probably due to failed allocations)
  1184. * requires that we just give up.
  1185. */
  1186. PORT_FreeArena (our_pool, PR_FALSE);
  1187. return NULL;
  1188. }
  1189. return cx;
  1190. }
  1191. /*
  1192. * XXX Do we need a FilterProc, too?
  1193. */
  1194. void
  1195. SEC_ASN1EncoderSetNotifyProc (SEC_ASN1EncoderContext *cx,
  1196. SEC_ASN1NotifyProc fn, void *arg)
  1197. {
  1198. cx->notify_proc = fn;
  1199. cx->notify_arg = arg;
  1200. }
  1201. void
  1202. SEC_ASN1EncoderClearNotifyProc (SEC_ASN1EncoderContext *cx)
  1203. {
  1204. cx->notify_proc = NULL;
  1205. cx->notify_arg = NULL; /* not necessary; just being clean */
  1206. }
  1207. void
  1208. SEC_ASN1EncoderAbort(SEC_ASN1EncoderContext *cx, int error)
  1209. {
  1210. PORT_Assert(cx);
  1211. PORT_SetError(error);
  1212. cx->status = encodeError;
  1213. }
  1214. void
  1215. SEC_ASN1EncoderSetStreaming (SEC_ASN1EncoderContext *cx)
  1216. {
  1217. /* XXX is there a way to check that we are "between" fields here? */
  1218. cx->streaming = PR_TRUE;
  1219. }
  1220. void
  1221. SEC_ASN1EncoderClearStreaming (SEC_ASN1EncoderContext *cx)
  1222. {
  1223. /* XXX is there a way to check that we are "between" fields here? */
  1224. cx->streaming = PR_FALSE;
  1225. }
  1226. void
  1227. SEC_ASN1EncoderSetTakeFromBuf (SEC_ASN1EncoderContext *cx)
  1228. {
  1229. /*
  1230. * XXX is there a way to check that we are "between" fields here? this
  1231. * needs to include a check for being in between groups of items in
  1232. * a SET_OF or SEQUENCE_OF.
  1233. */
  1234. PORT_Assert (cx->streaming);
  1235. cx->from_buf = PR_TRUE;
  1236. }
  1237. void
  1238. SEC_ASN1EncoderClearTakeFromBuf (SEC_ASN1EncoderContext *cx)
  1239. {
  1240. /* we should actually be taking from buf *now* */
  1241. PORT_Assert (cx->from_buf);
  1242. if (! cx->from_buf) /* if not, just do nothing */
  1243. return;
  1244. cx->from_buf = PR_FALSE;
  1245. if (cx->status == needBytes) {
  1246. cx->status = keepGoing;
  1247. cx->current->place = afterContents;
  1248. }
  1249. }
  1250. SECStatus
  1251. SEC_ASN1Encode (const void *src, const SEC_ASN1Template *theTemplate,
  1252. SEC_ASN1WriteProc output_proc, void *output_arg)
  1253. {
  1254. SEC_ASN1EncoderContext *ecx;
  1255. SECStatus rv;
  1256. ecx = SEC_ASN1EncoderStart (src, theTemplate, output_proc, output_arg);
  1257. if (ecx == NULL)
  1258. return SECFailure;
  1259. rv = SEC_ASN1EncoderUpdate (ecx, NULL, 0);
  1260. SEC_ASN1EncoderFinish (ecx);
  1261. return rv;
  1262. }
  1263. /*
  1264. * XXX depth and data_kind are unused; is there a PC way to silence warnings?
  1265. * (I mean "politically correct", not anything to do with intel/win platform)
  1266. */
  1267. static void
  1268. sec_asn1e_encode_item_count (void *arg, const char *buf, unsigned long len,
  1269. int depth, SEC_ASN1EncodingPart data_kind)
  1270. {
  1271. unsigned long *count;
  1272. count = (unsigned long*)arg;
  1273. PORT_Assert (count != NULL);
  1274. *count += len;
  1275. }
  1276. /* XXX depth and data_kind are unused; is there a PC way to silence warnings? */
  1277. static void
  1278. sec_asn1e_encode_item_store (void *arg, const char *buf, unsigned long len,
  1279. int depth, SEC_ASN1EncodingPart data_kind)
  1280. {
  1281. SECItem *dest;
  1282. dest = (SECItem*)arg;
  1283. PORT_Assert (dest != NULL);
  1284. PORT_Memcpy (dest->data + dest->len, buf, len);
  1285. dest->len += len;
  1286. }
  1287. /*
  1288. * Allocate an entire SECItem, or just the data part of it, to hold
  1289. * "len" bytes of stuff. Allocate from the given pool, if specified,
  1290. * otherwise just do a vanilla PORT_Alloc.
  1291. *
  1292. * XXX This seems like a reasonable general-purpose function (for SECITEM_)?
  1293. */
  1294. static SECItem *
  1295. sec_asn1e_allocate_item (PRArenaPool *poolp, SECItem *dest, unsigned long len)
  1296. {
  1297. if (poolp != NULL) {
  1298. void *release;
  1299. release = PORT_ArenaMark (poolp);
  1300. if (dest == NULL)
  1301. dest = (SECItem*)PORT_ArenaAlloc (poolp, sizeof(SECItem));
  1302. if (dest != NULL) {
  1303. dest->data = (unsigned char*)PORT_ArenaAlloc (poolp, len);
  1304. if (dest->data == NULL) {
  1305. dest = NULL;
  1306. }
  1307. }
  1308. if (dest == NULL) {
  1309. /* one or both allocations failed; release everything */
  1310. PORT_ArenaRelease (poolp, release);
  1311. } else {
  1312. /* everything okay; unmark the arena */
  1313. PORT_ArenaUnmark (poolp, release);
  1314. }
  1315. } else {
  1316. SECItem *indest;
  1317. indest = dest;
  1318. if (dest == NULL)
  1319. dest = (SECItem*)PORT_Alloc (sizeof(SECItem));
  1320. if (dest != NULL) {
  1321. dest->type = siBuffer;
  1322. dest->data = (unsigned char*)PORT_Alloc (len);
  1323. if (dest->data == NULL) {
  1324. if (indest == NULL)
  1325. PORT_Free (dest);
  1326. dest = NULL;
  1327. }
  1328. }
  1329. }
  1330. return dest;
  1331. }
  1332. SECItem *
  1333. SEC_ASN1EncodeItem (PRArenaPool *poolp, SECItem *dest, const void *src,
  1334. const SEC_ASN1Template *theTemplate)
  1335. {
  1336. unsigned long encoding_length;
  1337. SECStatus rv;
  1338. PORT_Assert (dest == NULL || dest->data == NULL);
  1339. encoding_length = 0;
  1340. rv = SEC_ASN1Encode (src, theTemplate,
  1341. sec_asn1e_encode_item_count, &encoding_length);
  1342. if (rv != SECSuccess)
  1343. return NULL;
  1344. dest = sec_asn1e_allocate_item (poolp, dest, encoding_length);
  1345. if (dest == NULL)
  1346. return NULL;
  1347. /* XXX necessary? This really just checks for a bug in the allocate fn */
  1348. PORT_Assert (dest->data != NULL);
  1349. if (dest->data == NULL)
  1350. return NULL;
  1351. dest->len = 0;
  1352. (void) SEC_ASN1Encode (src, theTemplate, sec_asn1e_encode_item_store, dest);
  1353. PORT_Assert (encoding_length == dest->len);
  1354. return dest;
  1355. }
  1356. static SECItem *
  1357. sec_asn1e_integer(PRArenaPool *poolp, SECItem *dest, unsigned long value,
  1358. PRBool is_unsigned)
  1359. {
  1360. unsigned long copy;
  1361. unsigned char sign;
  1362. int len = 0;
  1363. /*
  1364. * Determine the length of the encoded value (minimum of 1).
  1365. */
  1366. copy = value;
  1367. do {
  1368. len++;
  1369. sign = (unsigned char)(copy & 0x80);
  1370. copy >>= 8;
  1371. } while (copy);
  1372. /*
  1373. * If 'value' is non-negative, and the high bit of the last
  1374. * byte we counted was set, we need to add one to the length so
  1375. * we put a high-order zero byte in the encoding.
  1376. */
  1377. if (sign && (is_unsigned || (long)value >= 0))
  1378. len++;
  1379. /*
  1380. * Allocate the item (if necessary) and the data pointer within.
  1381. */
  1382. dest = sec_asn1e_allocate_item (poolp, dest, len);
  1383. if (dest == NULL)
  1384. return NULL;
  1385. /*
  1386. * Store the value, byte by byte, in the item.
  1387. */
  1388. dest->len = len;
  1389. while (len) {
  1390. dest->data[--len] = (unsigned char)value;
  1391. value >>= 8;
  1392. }
  1393. PORT_Assert (value == 0);
  1394. return dest;
  1395. }
  1396. SECItem *
  1397. SEC_ASN1EncodeInteger(PRArenaPool *poolp, SECItem *dest, long value)
  1398. {
  1399. return sec_asn1e_integer (poolp, dest, (unsigned long) value, PR_FALSE);
  1400. }
  1401. SECItem *
  1402. SEC_ASN1EncodeUnsignedInteger(PRArenaPool *poolp,
  1403. SECItem *dest, unsigned long value)
  1404. {
  1405. return sec_asn1e_integer (poolp, dest, value, PR_TRUE);
  1406. }