secasn1d.c
来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 2,402 行 · 第 1/5 页
C
2,402 行
/* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is the Netscape security libraries. * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1994-2000 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL"), in which case the provisions of the GPL are applicable * instead of those above. If you wish to allow use of your * version of this file only under the terms of the GPL and not to * allow others to use your version of this file under the MPL, * indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by * the GPL. If you do not delete the provisions above, a recipient * may use your version of this file under either the MPL or the * GPL. *//* * Support for DEcoding ASN.1 data based on BER/DER (Basic/Distinguished * Encoding Rules). * * $Id: secasn1d.c,v 1.4 2000/06/20 13:24:01 chrisk%netscape.com Exp $ */#include "secasn1.h"#include "secerr.h"typedef enum { beforeIdentifier, duringIdentifier, afterIdentifier, beforeLength, duringLength, afterLength, beforeBitString, duringBitString, duringConstructedString, duringGroup, duringLeaf, duringSaveEncoding, duringSequence, afterConstructedString, afterGroup, afterExplicit, afterImplicit, afterInline, afterPointer, afterSaveEncoding, beforeEndOfContents, duringEndOfContents, afterEndOfContents, beforeChoice, duringChoice, afterChoice, notInUse} sec_asn1d_parse_place;#ifdef DEBUG_ASN1D_STATESstatic const char *place_names[] = { "beforeIdentifier", "duringIdentifier", "afterIdentifier", "beforeLength", "duringLength", "afterLength", "beforeBitString", "duringBitString", "duringConstructedString", "duringGroup", "duringLeaf", "duringSaveEncoding", "duringSequence", "afterConstructedString", "afterGroup", "afterExplicit", "afterImplicit", "afterInline", "afterPointer", "afterSaveEncoding", "beforeEndOfContents", "duringEndOfContents", "afterEndOfContents", "beforeChoice", "duringChoice", "afterChoice", "notInUse"};#endif /* DEBUG_ASN1D_STATES */typedef enum { allDone, decodeError, keepGoing, needBytes} sec_asn1d_parse_status;struct subitem { const void *data; unsigned long len; /* only used for substrings */ struct subitem *next;};typedef struct sec_asn1d_state_struct { SEC_ASN1DecoderContext *top; const SEC_ASN1Template *theTemplate; void *dest; void *our_mark; /* free on completion */ struct sec_asn1d_state_struct *parent; /* aka prev */ struct sec_asn1d_state_struct *child; /* aka next */ sec_asn1d_parse_place place; /* * XXX explain the next fields as clearly as possible... */ unsigned char found_tag_modifiers; unsigned char expect_tag_modifiers; unsigned long check_tag_mask; unsigned long found_tag_number; unsigned long expect_tag_number; unsigned long underlying_kind; unsigned long contents_length; unsigned long pending; unsigned long consumed; int depth; /* * Bit strings have their length adjusted -- the first octet of the * contents contains a value between 0 and 7 which says how many bits * at the end of the octets are not actually part of the bit string; * when parsing bit strings we put that value here because we need it * later, for adjustment of the length (when the whole string is done). */ unsigned int bit_string_unused_bits; /* * The following are used for indefinite-length constructed strings. */ struct subitem *subitems_head; struct subitem *subitems_tail; PRPackedBool allocate, /* when true, need to allocate the destination */ endofcontents, /* this state ended up parsing end-of-contents octets */ explicit, /* we are handling an explicit header */ indefinite, /* the current item has indefinite-length encoding */ missing, /* an optional field that was not present */ optional, /* the template says this field may be omitted */ substring; /* this is a substring of a constructed string */} sec_asn1d_state;#define IS_HIGH_TAG_NUMBER(n) ((n) == SEC_ASN1_HIGH_TAG_NUMBER)#define LAST_TAG_NUMBER_BYTE(b) (((b) & 0x80) == 0)#define TAG_NUMBER_BITS 7#define TAG_NUMBER_MASK 0x7f#define LENGTH_IS_SHORT_FORM(b) (((b) & 0x80) == 0)#define LONG_FORM_LENGTH(b) ((b) & 0x7f)#define HIGH_BITS(field,cnt) ((field) >> ((sizeof(field) * 8) - (cnt)))/* * An "outsider" will have an opaque pointer to this, created by calling * SEC_ASN1DecoderStart(). It will be passed back in to all subsequent * calls to SEC_ASN1DecoderUpdate(), and when done it is passed to * SEC_ASN1DecoderFinish(). */struct sec_DecoderContext_struct { PRArenaPool *our_pool; /* for our internal allocs */ PRArenaPool *their_pool; /* for destination structure allocs */#ifdef SEC_ASN1D_FREE_ON_ERROR /* * XXX see comment below (by same * ifdef) that explains why this * does not work (need more smarts * in order to free back to mark) */ /* * XXX how to make their_mark work in the case where they do NOT * give us a pool pointer? */ void *their_mark; /* free on error */#endif sec_asn1d_state *current; sec_asn1d_parse_status status; SEC_ASN1NotifyProc notify_proc; /* call before/after handling field */ void *notify_arg; /* argument to notify_proc */ PRBool during_notify; /* true during call to notify_proc */ SEC_ASN1WriteProc filter_proc; /* pass field bytes to this */ void *filter_arg; /* argument to that function */ PRBool filter_only; /* do not allocate/store fields */};/* * XXX this is a fairly generic function that may belong elsewhere */static void *sec_asn1d_alloc (PRArenaPool *poolp, unsigned long len){ void *thing; if (poolp != NULL) { /* * Allocate from the pool. */ thing = PORT_ArenaAlloc (poolp, len); } else { /* * Allocate generically. */ thing = PORT_Alloc (len); } return thing;}/* * XXX this is a fairly generic function that may belong elsewhere */static void *sec_asn1d_zalloc (PRArenaPool *poolp, unsigned long len){ void *thing; thing = sec_asn1d_alloc (poolp, len); if (thing != NULL) PORT_Memset (thing, 0, len); return thing;}static sec_asn1d_state *sec_asn1d_push_state (SEC_ASN1DecoderContext *cx, const SEC_ASN1Template *theTemplate, void *dest, PRBool new_depth){ sec_asn1d_state *state, *new_state; state = cx->current; PORT_Assert (state == NULL || state->child == NULL); if (state != NULL) { PORT_Assert (state->our_mark == NULL); state->our_mark = PORT_ArenaMark (cx->our_pool); } new_state = (sec_asn1d_state*)sec_asn1d_zalloc (cx->our_pool, sizeof(*new_state)); if (new_state == NULL) { cx->status = decodeError; if (state != NULL) { PORT_ArenaRelease(cx->our_pool, state->our_mark); state->our_mark = NULL; } return NULL; } new_state->top = cx; new_state->parent = state; new_state->theTemplate = theTemplate; new_state->place = notInUse; if (dest != NULL) new_state->dest = (char *)dest + theTemplate->offset; if (state != NULL) { new_state->depth = state->depth; if (new_depth) new_state->depth++; state->child = new_state; } cx->current = new_state; return new_state;}static voidsec_asn1d_scrub_state (sec_asn1d_state *state){ /* * Some default "scrubbing". * XXX right set of initializations? */ state->place = beforeIdentifier; state->endofcontents = PR_FALSE; state->indefinite = PR_FALSE; state->missing = PR_FALSE; PORT_Assert (state->consumed == 0);}static voidsec_asn1d_notify_before (SEC_ASN1DecoderContext *cx, void *dest, int depth){ if (cx->notify_proc == NULL) return; cx->during_notify = PR_TRUE; (* cx->notify_proc) (cx->notify_arg, PR_TRUE, dest, depth); cx->during_notify = PR_FALSE;}static voidsec_asn1d_notify_after (SEC_ASN1DecoderContext *cx, void *dest, int depth){ if (cx->notify_proc == NULL) return; cx->during_notify = PR_TRUE; (* cx->notify_proc) (cx->notify_arg, PR_FALSE, dest, depth); cx->during_notify = PR_FALSE;}static sec_asn1d_state *sec_asn1d_init_state_based_on_template (sec_asn1d_state *state){ PRBool explicit, optional, universal; unsigned char expect_tag_modifiers; unsigned long encode_kind, under_kind; unsigned long check_tag_mask, expect_tag_number; /* XXX Check that both of these tests are really needed/appropriate. */ if (state == NULL || state->top->status == decodeError) return state; encode_kind = state->theTemplate->kind; if (encode_kind & SEC_ASN1_SAVE) { /* * This is a "magic" field that saves away all bytes, allowing * the immediately following field to still be decoded from this * same spot -- sort of a fork. */ /* check that there are no extraneous bits */ PORT_Assert (encode_kind == SEC_ASN1_SAVE); if (state->top->filter_only) { /* * If we are not storing, then we do not do the SAVE field * at all. Just move ahead to the "real" field instead, * doing the appropriate notify calls before and after. */ sec_asn1d_notify_after (state->top, state->dest, state->depth); /* * Since we are not storing, allow for our current dest value * to be NULL. (This might not actually occur, but right now I * cannot convince myself one way or the other.) If it is NULL, * assume that our parent dest can help us out. */ if (state->dest == NULL) state->dest = state->parent->dest; else state->dest = (char *)state->dest - state->theTemplate->offset; state->theTemplate++; if (state->dest != NULL) state->dest = (char *)state->dest + state->theTemplate->offset; sec_asn1d_notify_before (state->top, state->dest, state->depth); encode_kind = state->theTemplate->kind; PORT_Assert ((encode_kind & SEC_ASN1_SAVE) == 0); } else { sec_asn1d_scrub_state (state); state->place = duringSaveEncoding; state = sec_asn1d_push_state (state->top, SEC_AnyTemplate, state->dest, PR_FALSE); if (state != NULL) state = sec_asn1d_init_state_based_on_template (state); return state; } } universal = ((encode_kind & SEC_ASN1_CLASS_MASK) == SEC_ASN1_UNIVERSAL) ? PR_TRUE : PR_FALSE; explicit = (encode_kind & SEC_ASN1_EXPLICIT) ? PR_TRUE : PR_FALSE; encode_kind &= ~SEC_ASN1_EXPLICIT; optional = (encode_kind & SEC_ASN1_OPTIONAL) ? PR_TRUE : PR_FALSE; encode_kind &= ~SEC_ASN1_OPTIONAL; PORT_Assert (!(explicit && universal)); /* bad templates */ encode_kind &= ~SEC_ASN1_DYNAMIC; encode_kind &= ~SEC_ASN1_MAY_STREAM; if( encode_kind & SEC_ASN1_CHOICE ) {#if 0 /* XXX remove? */ sec_asn1d_state *child = sec_asn1d_push_state(state->top, state->theTemplate, state->dest, PR_FALSE); if( (sec_asn1d_state *)NULL == child ) { return (sec_asn1d_state *)NULL; } child->allocate = state->allocate; child->place = beforeChoice; return child;#else state->place = beforeChoice; return state;#endif } if ((encode_kind & (SEC_ASN1_POINTER | SEC_ASN1_INLINE)) || (!universal && !explicit)) { const SEC_ASN1Template *subt; void *dest; PRBool child_allocate; PORT_Assert ((encode_kind & (SEC_ASN1_ANY | SEC_ASN1_SKIP)) == 0); sec_asn1d_scrub_state (state); child_allocate = PR_FALSE; if (encode_kind & SEC_ASN1_POINTER) { /* * A POINTER means we need to allocate the destination for * this field. But, since it may also be an optional field, * we defer the allocation until later; we just record that * it needs to be done. * * There are two possible scenarios here -- one is just a * plain POINTER (kind of like INLINE, except with allocation) * and the other is an implicitly-tagged POINTER. We don't * need to do anything special here for the two cases, but * since the template definition can be tricky, we do check * that there are no extraneous bits set in encode_kind. * * XXX The same conditions which assert should set an error. */ if (universal) { /* * "universal" means this entry is a standalone POINTER; * there should be no other bits set in encode_kind. */ PORT_Assert (encode_kind == SEC_ASN1_POINTER); } else { /* * If we get here we have an implicitly-tagged field * that needs to be put into a POINTER. The subtemplate * will determine how to decode the field, but encode_kind * describes the (implicit) tag we are looking for. * The non-tag bits of encode_kind will be ignored by * the code below; none of them should be set, however, * except for the POINTER bit itself -- so check that. */ PORT_Assert ((encode_kind & ~SEC_ASN1_TAG_MASK) == SEC_ASN1_POINTER); } if (!state->top->filter_only) child_allocate = PR_TRUE; dest = NULL; state->place = afterPointer; } else {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?