secasn1e.c
来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 1,469 行 · 第 1/3 页
C
1,469 行
child = state->child; group = *(void ***)state->src; /* * Find placement of current item. */ member = (char *)(state->child->src) - child->theTemplate->offset; while (*group != member) group++; /* * Move forward to next item. */ group++; if (*group == NULL) { /* * That was our last one; we are done now. */ child->place = notInUse; state->place = afterContents; return; } child->src = (char *)(*group) + child->theTemplate->offset; /* * Re-"push" child. */ sec_asn1e_scrub_state (child); state->top->current = child;}/* * We are moving along through a sequence; move forward by one, * (detecting end-of-sequence when it happens). */static voidsec_asn1e_next_in_sequence (sec_asn1e_state *state){ sec_asn1e_state *child; PORT_Assert (state->place == duringSequence); PORT_Assert (state->child != NULL); child = state->child; /* * Do the "after" field notification. */ sec_asn1e_notify_after (state->top, child->src, child->depth); /* * Move forward. */ child->theTemplate++; if (child->theTemplate->kind == 0) { /* * We are done with this sequence. */ child->place = notInUse; state->place = afterContents; return; } /* * Reset state and push. */ child->src = (char *)state->src + child->theTemplate->offset; /* * Do the "before" field notification. */ sec_asn1e_notify_before (state->top, child->src, child->depth); state->top->current = child; (void) sec_asn1e_init_state_based_on_template (child);}static voidsec_asn1e_after_contents (sec_asn1e_state *state){ PORT_Assert (state->place == afterContents); if (state->indefinite) sec_asn1e_write_end_of_contents_bytes (state); /* * Just make my parent be the current state. It will then clean * up after me and free me (or reuse me). */ state->top->current = state->parent;}/* * This function is called whether or not we are streaming; if we * *are* streaming, our caller can also instruct us to take bytes * from the passed-in buffer (at buf, for length len, which is likely * bytes but could even mean bits if the current field is a bit string). * If we have been so instructed, we will gobble up bytes from there * (rather than from our src structure) and output them, and then * we will just return, expecting to be called again -- either with * more bytes or after our caller has instructed us that we are done * (for now) with the buffer. */SECStatusSEC_ASN1EncoderUpdate (SEC_ASN1EncoderContext *cx, const char *buf, unsigned long len){ sec_asn1e_state *state; if (cx->status == needBytes) { PORT_Assert (buf != NULL && len != 0); cx->status = keepGoing; } while (cx->status == keepGoing) { state = cx->current; switch (state->place) { case beforeHeader: sec_asn1e_write_header (state); break; case duringContents: sec_asn1e_write_contents (state, buf, len); break; case duringGroup: sec_asn1e_next_in_group (state); break; case duringSequence: sec_asn1e_next_in_sequence (state); break; case afterContents: sec_asn1e_after_contents (state); break; case afterImplicit: case afterInline: case afterPointer: case afterChoice: /* * These states are more documentation than anything. * They just need to force a pop. */ PORT_Assert (!state->indefinite); state->place = afterContents; break; case notInUse: default: /* This is not an error, but rather a plain old BUG! */ PORT_Assert (0); cx->status = encodeError; break; } if (cx->status == encodeError) break; /* It might have changed, so we have to update our local copy. */ state = cx->current; /* If it is NULL, we have popped all the way to the top. */ if (state == NULL) { cx->status = allDone; break; } } if (cx->status == encodeError) { return SECFailure; } return SECSuccess;}voidSEC_ASN1EncoderFinish (SEC_ASN1EncoderContext *cx){ /* * XXX anything else that needs to be finished? */ PORT_FreeArena (cx->our_pool, PR_FALSE);}SEC_ASN1EncoderContext *SEC_ASN1EncoderStart (void *src, const SEC_ASN1Template *theTemplate, SEC_ASN1WriteProc output_proc, void *output_arg){ PRArenaPool *our_pool; SEC_ASN1EncoderContext *cx; our_pool = PORT_NewArena (SEC_ASN1_DEFAULT_ARENA_SIZE); if (our_pool == NULL) return NULL; cx = (SEC_ASN1EncoderContext*)PORT_ArenaZAlloc (our_pool, sizeof(*cx)); if (cx == NULL) { PORT_FreeArena (our_pool, PR_FALSE); return NULL; } cx->our_pool = our_pool; cx->output_proc = output_proc; cx->output_arg = output_arg; cx->status = keepGoing; if (sec_asn1e_push_state(cx, theTemplate, src, PR_FALSE) == NULL || sec_asn1e_init_state_based_on_template (cx->current) == NULL) { /* * Trouble initializing (probably due to failed allocations) * requires that we just give up. */ PORT_FreeArena (our_pool, PR_FALSE); return NULL; } return cx;}/* * XXX Do we need a FilterProc, too? */voidSEC_ASN1EncoderSetNotifyProc (SEC_ASN1EncoderContext *cx, SEC_ASN1NotifyProc fn, void *arg){ cx->notify_proc = fn; cx->notify_arg = arg;}voidSEC_ASN1EncoderClearNotifyProc (SEC_ASN1EncoderContext *cx){ cx->notify_proc = NULL; cx->notify_arg = NULL; /* not necessary; just being clean */}voidSEC_ASN1EncoderSetStreaming (SEC_ASN1EncoderContext *cx){ /* XXX is there a way to check that we are "between" fields here? */ cx->streaming = PR_TRUE;}voidSEC_ASN1EncoderClearStreaming (SEC_ASN1EncoderContext *cx){ /* XXX is there a way to check that we are "between" fields here? */ cx->streaming = PR_FALSE;}voidSEC_ASN1EncoderSetTakeFromBuf (SEC_ASN1EncoderContext *cx){ /* * XXX is there a way to check that we are "between" fields here? this * needs to include a check for being in between groups of items in * a SET_OF or SEQUENCE_OF. */ PORT_Assert (cx->streaming); cx->from_buf = PR_TRUE;}voidSEC_ASN1EncoderClearTakeFromBuf (SEC_ASN1EncoderContext *cx){ /* we should actually be taking from buf *now* */ PORT_Assert (cx->from_buf); if (! cx->from_buf) /* if not, just do nothing */ return; cx->from_buf = PR_FALSE; if (cx->status == needBytes) { cx->status = keepGoing; cx->current->place = afterContents; }}SECStatusSEC_ASN1Encode (void *src, const SEC_ASN1Template *theTemplate, SEC_ASN1WriteProc output_proc, void *output_arg){ SEC_ASN1EncoderContext *ecx; SECStatus rv; ecx = SEC_ASN1EncoderStart (src, theTemplate, output_proc, output_arg); if (ecx == NULL) return SECFailure; rv = SEC_ASN1EncoderUpdate (ecx, NULL, 0); SEC_ASN1EncoderFinish (ecx); return rv;}/* * XXX depth and data_kind are unused; is there a PC way to silence warnings? * (I mean "politically correct", not anything to do with intel/win platform) */static voidsec_asn1e_encode_item_count (void *arg, const char *buf, unsigned long len, int depth, SEC_ASN1EncodingPart data_kind){ unsigned long *count; count = (unsigned long*)arg; PORT_Assert (count != NULL); *count += len;}/* XXX depth and data_kind are unused; is there a PC way to silence warnings? */static voidsec_asn1e_encode_item_store (void *arg, const char *buf, unsigned long len, int depth, SEC_ASN1EncodingPart data_kind){ SECItem *dest; dest = (SECItem*)arg; PORT_Assert (dest != NULL); PORT_Memcpy (dest->data + dest->len, buf, len); dest->len += len;}/* * Allocate an entire SECItem, or just the data part of it, to hold * "len" bytes of stuff. Allocate from the given pool, if specified, * otherwise just do a vanilla PORT_Alloc. * * XXX This seems like a reasonable general-purpose function (for SECITEM_)? */static SECItem *sec_asn1e_allocate_item (PRArenaPool *poolp, SECItem *dest, unsigned long len){ if (poolp != NULL) { void *release; release = PORT_ArenaMark (poolp); if (dest == NULL) dest = (SECItem*)PORT_ArenaAlloc (poolp, sizeof(SECItem)); if (dest != NULL) { dest->data = (unsigned char*)PORT_ArenaAlloc (poolp, len); if (dest->data == NULL) { dest = NULL; } } if (dest == NULL) { /* one or both allocations failed; release everything */ PORT_ArenaRelease (poolp, release); } else { /* everything okay; unmark the arena */ PORT_ArenaUnmark (poolp, release); } } else { SECItem *indest; indest = dest; if (dest == NULL) dest = (SECItem*)PORT_Alloc (sizeof(SECItem)); if (dest != NULL) { dest->data = (unsigned char*)PORT_Alloc (len); if (dest->data == NULL) { if (indest == NULL) PORT_Free (dest); dest = NULL; } } } return dest;}SECItem *SEC_ASN1EncodeItem (PRArenaPool *poolp, SECItem *dest, void *src, const SEC_ASN1Template *theTemplate){ unsigned long encoding_length; SECStatus rv; PORT_Assert (dest == NULL || dest->data == NULL); encoding_length = 0; rv = SEC_ASN1Encode (src, theTemplate, sec_asn1e_encode_item_count, &encoding_length); if (rv != SECSuccess) return NULL; dest = sec_asn1e_allocate_item (poolp, dest, encoding_length); if (dest == NULL) return NULL; /* XXX necessary? This really just checks for a bug in the allocate fn */ PORT_Assert (dest->data != NULL); if (dest->data == NULL) return NULL; dest->len = 0; (void) SEC_ASN1Encode (src, theTemplate, sec_asn1e_encode_item_store, dest); PORT_Assert (encoding_length == dest->len); return dest;}static SECItem *sec_asn1e_integer(PRArenaPool *poolp, SECItem *dest, unsigned long value, PRBool make_unsigned){ unsigned long copy; unsigned char sign; int len = 0; /* * Determine the length of the encoded value (minimum of 1). */ copy = value; do { len++; sign = copy & 0x80; copy >>= 8; } while (copy); /* * If this is an unsigned encoding, and the high bit of the last * byte we counted was set, we need to add one to the length so * we put a high-order zero byte in the encoding. */ if (sign && make_unsigned) len++; /* * Allocate the item (if necessary) and the data pointer within. */ dest = sec_asn1e_allocate_item (poolp, dest, len); if (dest == NULL) return NULL; /* * Store the value, byte by byte, in the item. */ dest->len = len; while (len) { dest->data[--len] = value; value >>= 8; } PORT_Assert (value == 0); return dest;}SECItem *SEC_ASN1EncodeInteger(PRArenaPool *poolp, SECItem *dest, long value){ return sec_asn1e_integer (poolp, dest, (unsigned long) value, PR_FALSE);}extern SECItem *SEC_ASN1EncodeUnsignedInteger(PRArenaPool *poolp, SECItem *dest, unsigned long value){ return sec_asn1e_integer (poolp, dest, value, PR_TRUE);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?