secasn1e.c
来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 1,469 行 · 第 1/3 页
C
1,469 行
encode_kind &= ~SEC_ASN1_OPTIONAL; PORT_Assert (!(explicit && universal)); /* bad templates */ may_stream = (encode_kind & SEC_ASN1_MAY_STREAM) ? PR_TRUE : PR_FALSE; encode_kind &= ~SEC_ASN1_MAY_STREAM; /* Just clear this to get it out of the way; we do not need it here */ encode_kind &= ~SEC_ASN1_DYNAMIC; if( encode_kind & SEC_ASN1_CHOICE ) { void *src2; int indx = sec_asn1e_which_choice(src, theTemplate); if( 0 == indx ) { /* XXX set an error? "choice not found" */ /* state->top->status = encodeError; */ return 0; } src2 = (void *)((char *)src + theTemplate[indx].offset); return sec_asn1e_contents_length(&theTemplate[indx], src2, noheaderp); } if ((encode_kind & (SEC_ASN1_POINTER | SEC_ASN1_INLINE)) || !universal) { /* XXX any bits we want to disallow (PORT_Assert against) here? */ theTemplate = SEC_ASN1GetSubtemplate (theTemplate, src, PR_TRUE); if (encode_kind & SEC_ASN1_POINTER) { /* * XXX This used to PORT_Assert (encode_kind == SEC_ASN1_POINTER); * but that was too restrictive. This needs to be fixed, * probably copying what the decoder now checks for, and * adding a big comment here to explain what the checks mean. * Alternatively, the check here could be omitted altogether * just letting sec_asn1e_init_state_based_on_template * do it, since that routine can do better error handling, too. */ src = *(void **)src; if (src == NULL) { if (optional) *noheaderp = PR_TRUE; else *noheaderp = PR_FALSE; return 0; } } else if (encode_kind & SEC_ASN1_INLINE) { /* check that there are no extraneous bits */ PORT_Assert (encode_kind == SEC_ASN1_INLINE && !optional); } src = (char *)src + theTemplate->offset; if (explicit) { len = sec_asn1e_contents_length (theTemplate, src, noheaderp); if (len == 0 && optional) { *noheaderp = PR_TRUE; } else if (*noheaderp) { /* Okay, *we* do not want to add in a header, but our caller still does. */ *noheaderp = PR_FALSE; } else { /* if the inner content exists, our length is * len(identifier) + len(length) + len(innercontent) * XXX we currently assume len(identifier) == 1; * to support a high-tag-number this would need to be smarter. */ len += 1 + SEC_ASN1LengthLength (len); } return len; } underlying_kind = theTemplate->kind; underlying_kind &= ~SEC_ASN1_MAY_STREAM; /* XXX Should we recurse here? */ } else { underlying_kind = encode_kind; } /* This is only used in decoding; it plays no part in encoding. */ if (underlying_kind & SEC_ASN1_SAVE) { /* check that there are no extraneous bits */ PORT_Assert (underlying_kind == SEC_ASN1_SAVE); *noheaderp = PR_TRUE; return 0; } /* Having any of these bits is not expected here... */ PORT_Assert ((underlying_kind & (SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_INLINE | SEC_ASN1_POINTER | SEC_ASN1_DYNAMIC | SEC_ASN1_MAY_STREAM | SEC_ASN1_SAVE | SEC_ASN1_SKIP)) == 0); if( underlying_kind & SEC_ASN1_CHOICE ) { void *src2; int indx = sec_asn1e_which_choice(src, theTemplate); if( 0 == indx ) { /* XXX set an error? "choice not found" */ /* state->top->status = encodeError; */ return 0; } src2 = (void *)((char *)src - theTemplate->offset + theTemplate[indx].offset); len = sec_asn1e_contents_length(&theTemplate[indx], src2, noheaderp); } else switch (underlying_kind) { case SEC_ASN1_SEQUENCE_OF: case SEC_ASN1_SET_OF: { const SEC_ASN1Template *tmpt; void *sub_src; unsigned long sub_len; void **group; len = 0; group = *(void ***)src; if (group == NULL) break; tmpt = SEC_ASN1GetSubtemplate (theTemplate, src, PR_TRUE); for (; *group != NULL; group++) { sub_src = (char *)(*group) + tmpt->offset; sub_len = sec_asn1e_contents_length (tmpt, sub_src, noheaderp); len += sub_len; /* * XXX The 1 below is the presumed length of the identifier; * to support a high-tag-number this would need to be smarter. */ if (!*noheaderp) len += 1 + SEC_ASN1LengthLength (sub_len); } } break; case SEC_ASN1_SEQUENCE: case SEC_ASN1_SET: { const SEC_ASN1Template *tmpt; void *sub_src; unsigned long sub_len; len = 0; for (tmpt = theTemplate + 1; tmpt->kind; tmpt++) { sub_src = (char *)src + tmpt->offset; sub_len = sec_asn1e_contents_length (tmpt, sub_src, noheaderp); len += sub_len; /* * XXX The 1 below is the presumed length of the identifier; * to support a high-tag-number this would need to be smarter. */ if (!*noheaderp) len += 1 + SEC_ASN1LengthLength (sub_len); } } break; case SEC_ASN1_BIT_STRING: /* convert bit length to byte */ len = (((SECItem *)src)->len + 7) >> 3; /* bit string contents involve an extra octet */ if (len) len++; break; default: len = ((SECItem *)src)->len; if (may_stream && len == 0) len = 1; /* if we're streaming, we may have a secitem w/len 0 as placeholder */ break; } if ((len == 0 && optional) || underlying_kind == SEC_ASN1_ANY) *noheaderp = PR_TRUE; else *noheaderp = PR_FALSE; return len;}static voidsec_asn1e_write_header (sec_asn1e_state *state){ unsigned long contents_length; unsigned char tag_number, tag_modifiers; PRBool noheader; PORT_Assert (state->place == beforeHeader); tag_number = state->tag_number; tag_modifiers = state->tag_modifiers; if (state->underlying_kind == SEC_ASN1_ANY) { state->place = duringContents; return; } if( state->underlying_kind & SEC_ASN1_CHOICE ) { void *src2; int indx = sec_asn1e_which_choice(state->src, state->theTemplate); if( 0 == indx ) { /* XXX set an error? "choice not found" */ state->top->status = encodeError; return; } state->place = afterChoice; state = sec_asn1e_push_state(state->top, &state->theTemplate[indx], state->src, PR_TRUE); if( (sec_asn1e_state *)NULL != state ) { /* * Do the "before" field notification. */ sec_asn1e_notify_before (state->top, state->src, state->depth); state = sec_asn1e_init_state_based_on_template (state); } return; } /* * We are doing a definite-length encoding. First we have to * walk the data structure to calculate the entire contents length. */ contents_length = sec_asn1e_contents_length (state->theTemplate, state->src, &noheader); /* * We might be told explicitly not to put out a header. * But it can also be the case, via a pushed subtemplate, that * sec_asn1e_contents_length could not know that this field is * really optional. So check for that explicitly, too. */ if (noheader || (contents_length == 0 && state->optional)) { state->place = afterContents; if (state->top->streaming && state->may_stream && state->top->from_buf) /* we did not find an optional indefinite string, so we don't encode it. * However, if TakeFromBuf is on, we stop here anyway to give our caller * a chance to intercept at the same point where we would stop if the * field were present. */ state->top->status = needBytes; return; } if (state->top->streaming && state->may_stream && (state->top->from_buf || !state->is_string)) { /* * We need to put out an indefinite-length encoding. */ state->indefinite = PR_TRUE; /* * The only universal types that can be constructed are SETs, * SEQUENCEs, and strings; so check that it is one of those, * or that it is not universal (e.g. context-specific). */ PORT_Assert ((tag_number == SEC_ASN1_SET) || (tag_number == SEC_ASN1_SEQUENCE) || ((tag_modifiers & SEC_ASN1_CLASS_MASK) != 0) || state->is_string); tag_modifiers |= SEC_ASN1_CONSTRUCTED; contents_length = 0; } sec_asn1e_write_identifier_bytes (state, tag_number | tag_modifiers); sec_asn1e_write_length_bytes (state, contents_length, state->indefinite); if (contents_length == 0 && !state->indefinite) { /* * If no real contents to encode, then we are done with this field. */ state->place = afterContents; return; } /* * An EXPLICIT is nothing but an outer header, which we have already * written. Now we need to do the inner header and contents. */ if (state->explicit) { state->place = afterContents; state = sec_asn1e_push_state (state->top, SEC_ASN1GetSubtemplate(state->theTemplate, state->src, PR_TRUE), state->src, PR_TRUE); if (state != NULL) state = sec_asn1e_init_state_based_on_template (state); return; } switch (state->underlying_kind) { case SEC_ASN1_SET_OF: case SEC_ASN1_SEQUENCE_OF: /* * We need to push a child to handle each member. */ { void **group; const SEC_ASN1Template *subt; group = *(void ***)state->src; if (group == NULL || *group == NULL) { /* * Group is empty; we are done. */ state->place = afterContents; return; } state->place = duringGroup; subt = SEC_ASN1GetSubtemplate (state->theTemplate, state->src, PR_TRUE); state = sec_asn1e_push_state (state->top, subt, *group, PR_TRUE); if (state != NULL) state = sec_asn1e_init_state_based_on_template (state); } break; case SEC_ASN1_SEQUENCE: case SEC_ASN1_SET: /* * We need to push a child to handle the individual fields. */ state->place = duringSequence; state = sec_asn1e_push_state (state->top, state->theTemplate + 1, state->src, PR_TRUE); if (state != NULL) { /* * Do the "before" field notification. */ sec_asn1e_notify_before (state->top, state->src, state->depth); state = sec_asn1e_init_state_based_on_template (state); } break; default: /* * I think we do not need to do anything else. * XXX Correct? */ state->place = duringContents; break; }}static voidsec_asn1e_write_contents (sec_asn1e_state *state, const char *buf, unsigned long len){ PORT_Assert (state->place == duringContents); if (state->top->from_buf) { /* * Probably they just turned on "take from buf", but have not * yet given us any bytes. If there is nothing in the buffer * then we have nothing to do but return and wait. */ if (buf == NULL || len == 0) { state->top->status = needBytes; return; } /* * We are streaming, reading from a passed-in buffer. * This means we are encoding a simple string or an ANY. * For the former, we need to put out a substring, with its * own identifier and length. For an ANY, we just write it * out as is (our caller is required to ensure that it * is a properly encoded entity). */ PORT_Assert (state->is_string); /* includes ANY */ if (state->underlying_kind != SEC_ASN1_ANY) { unsigned char identifier; /* * Create the identifier based on underlying_kind. We cannot * use tag_number and tag_modifiers because this can be an * implicitly encoded field. In that case, the underlying * substrings *are* encoded with their real tag. */ identifier = state->underlying_kind & SEC_ASN1_TAG_MASK; /* * The underlying kind should just be a simple string; there * should be no bits like CONTEXT_SPECIFIC or CONSTRUCTED set. */ PORT_Assert ((identifier & SEC_ASN1_TAGNUM_MASK) == identifier); /* * Write out the tag and length for the substring. */ sec_asn1e_write_identifier_bytes (state, identifier); if (state->underlying_kind == SEC_ASN1_BIT_STRING) { char byte; /* * Assume we have a length in bytes but we need to output * a proper bit string. This interface only works for bit * strings that are full multiples of 8. If support for * real, variable length bit strings is needed then the * caller will have to know to pass in a bit length instead * of a byte length and then this code will have to * perform the encoding necessary (length written is length * in bytes plus 1, and the first octet of string is the * number of bits remaining between the end of the bit * string and the next byte boundary). */ sec_asn1e_write_length_bytes (state, len + 1, PR_FALSE); byte = 0; sec_asn1e_write_contents_bytes (state, &byte, 1); } else { sec_asn1e_write_length_bytes (state, len, PR_FALSE); } } sec_asn1e_write_contents_bytes (state, buf, len); state->top->status = needBytes; } else { switch (state->underlying_kind) { case SEC_ASN1_SET: case SEC_ASN1_SEQUENCE: PORT_Assert (0); break; case SEC_ASN1_BIT_STRING: { SECItem *item; char rem; item = (SECItem *)state->src; len = (item->len + 7) >> 3; rem = (len << 3) - item->len; /* remaining bits */ sec_asn1e_write_contents_bytes (state, &rem, 1); sec_asn1e_write_contents_bytes (state, (char *) item->data, len); } break; case SEC_ASN1_BMP_STRING: /* The number of bytes must be divisable by 2 */ if ((((SECItem *)state->src)->len) % 2) { SEC_ASN1EncoderContext *cx; cx = state->top; cx->status = encodeError; break; } /* otherwise, fall through to write the content */ goto process_string; case SEC_ASN1_UNIVERSAL_STRING: /* The number of bytes must be divisable by 4 */ if ((((SECItem *)state->src)->len) % 4) { SEC_ASN1EncoderContext *cx; cx = state->top; cx->status = encodeError; break; } /* otherwise, fall through to write the content */ goto process_string; process_string: default: { SECItem *item; item = (SECItem *)state->src; sec_asn1e_write_contents_bytes (state, (char *) item->data, item->len); } break; } state->place = afterContents; }}/* * We are doing a SET OF or SEQUENCE OF, and have just finished an item. */static voidsec_asn1e_next_in_group (sec_asn1e_state *state){ sec_asn1e_state *child; void **group; void *member; PORT_Assert (state->place == duringGroup); PORT_Assert (state->child != NULL);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?