📄 tasn_dec.c
字号:
if(!*val) *val = (ASN1_VALUE *)sk_new_null(); else { /* We've got a valid STACK: free up any items present */ STACK *sktmp = (STACK *)*val; ASN1_VALUE *vtmp; while(sk_num(sktmp) > 0) { vtmp = (ASN1_VALUE *)sk_pop(sktmp); ASN1_item_ex_free(&vtmp, ASN1_ITEM_ptr(tt->item)); } } if(!*val) { ASN1err(ASN1_F_ASN1_TEMPLATE_EX_D2I, ERR_R_MALLOC_FAILURE); goto err; } /* Read as many items as we can */ while(len > 0) { ASN1_VALUE *skfield; q = p; /* See if EOC found */ if(asn1_check_eoc(&p, len)) { if(!sk_eoc) { ASN1err(ASN1_F_ASN1_TEMPLATE_D2I, ASN1_R_UNEXPECTED_EOC); goto err; } len -= p - q; sk_eoc = 0; break; } skfield = NULL; if(!ASN1_item_ex_d2i(&skfield, &p, len, ASN1_ITEM_ptr(tt->item), -1, 0, 0, ctx)) { ASN1err(ASN1_F_ASN1_TEMPLATE_D2I, ERR_R_NESTED_ASN1_ERROR); goto err; } len -= p - q; if(!sk_push((STACK *)*val, (char *)skfield)) { ASN1err(ASN1_F_ASN1_TEMPLATE_D2I, ERR_R_MALLOC_FAILURE); goto err; } } if(sk_eoc) { ASN1err(ASN1_F_ASN1_TEMPLATE_D2I, ASN1_R_MISSING_EOC); goto err; } } else if(flags & ASN1_TFLG_IMPTAG) { /* IMPLICIT tagging */ ret = ASN1_item_ex_d2i(val, &p, len, ASN1_ITEM_ptr(tt->item), tt->tag, aclass, opt, ctx); if(!ret) { ASN1err(ASN1_F_ASN1_TEMPLATE_D2I, ERR_R_NESTED_ASN1_ERROR); goto err; } else if(ret == -1) return -1; } else { /* Nothing special */ ret = ASN1_item_ex_d2i(val, &p, len, ASN1_ITEM_ptr(tt->item), -1, 0, opt, ctx); if(!ret) { ASN1err(ASN1_F_ASN1_TEMPLATE_D2I, ERR_R_NESTED_ASN1_ERROR); goto err; } else if(ret == -1) return -1; } *in = p; return 1; err: ASN1_template_free(val, tt); *val = NULL; return 0;}static int asn1_d2i_ex_primitive(ASN1_VALUE **pval, unsigned char **in, long inlen, const ASN1_ITEM *it, int tag, int aclass, char opt, ASN1_TLC *ctx){ int ret = 0, utype; long plen; char cst, inf, free_cont = 0; unsigned char *p; BUF_MEM buf; unsigned char *cont = NULL; long len; if(!pval) { ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ASN1_R_ILLEGAL_NULL); return 0; /* Should never happen */ } if(it->itype == ASN1_ITYPE_MSTRING) { utype = tag; tag = -1; } else utype = it->utype; if(utype == V_ASN1_ANY) { /* If type is ANY need to figure out type from tag */ unsigned char oclass; if(tag >= 0) { ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ASN1_R_ILLEGAL_TAGGED_ANY); return 0; } if(opt) { ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ASN1_R_ILLEGAL_OPTIONAL_ANY); return 0; } p = *in; ret = asn1_check_tlen(NULL, &utype, &oclass, NULL, NULL, &p, inlen, -1, 0, 0, ctx); if(!ret) { ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ERR_R_NESTED_ASN1_ERROR); return 0; } if(oclass != V_ASN1_UNIVERSAL) utype = V_ASN1_OTHER; } if(tag == -1) { tag = utype; aclass = V_ASN1_UNIVERSAL; } p = *in; /* Check header */ ret = asn1_check_tlen(&plen, NULL, NULL, &inf, &cst, &p, inlen, tag, aclass, opt, ctx); if(!ret) { ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ERR_R_NESTED_ASN1_ERROR); return 0; } else if(ret == -1) return -1; /* SEQUENCE, SET and "OTHER" are left in encoded form */ if((utype == V_ASN1_SEQUENCE) || (utype == V_ASN1_SET) || (utype == V_ASN1_OTHER)) { /* Clear context cache for type OTHER because the auto clear when * we have a exact match wont work */ if(utype == V_ASN1_OTHER) { asn1_tlc_clear(ctx); /* SEQUENCE and SET must be constructed */ } else if(!cst) { ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ASN1_R_TYPE_NOT_CONSTRUCTED); return 0; } cont = *in; /* If indefinite length constructed find the real end */ if(inf) { if(!asn1_find_end(&p, plen, inf)) goto err; len = p - cont; } else { len = p - cont + plen; p += plen; buf.data = NULL; } } else if(cst) { buf.length = 0; buf.max = 0; buf.data = NULL; /* Should really check the internal tags are correct but * some things may get this wrong. The relevant specs * say that constructed string types should be OCTET STRINGs * internally irrespective of the type. So instead just check * for UNIVERSAL class and ignore the tag. */ if(!asn1_collect(&buf, &p, plen, inf, -1, V_ASN1_UNIVERSAL)) goto err; len = buf.length; /* Append a final null to string */ if(!BUF_MEM_grow_clean(&buf, len + 1)) { ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ERR_R_MALLOC_FAILURE); return 0; } buf.data[len] = 0; cont = (unsigned char *)buf.data; free_cont = 1; } else { cont = p; len = plen; p += plen; } /* We now have content length and type: translate into a structure */ if(!asn1_ex_c2i(pval, cont, len, utype, &free_cont, it)) goto err; *in = p; ret = 1; err: if(free_cont && buf.data) OPENSSL_free(buf.data); return ret;}/* Translate ASN1 content octets into a structure */int asn1_ex_c2i(ASN1_VALUE **pval, unsigned char *cont, int len, int utype, char *free_cont, const ASN1_ITEM *it){ ASN1_VALUE **opval = NULL; ASN1_STRING *stmp; ASN1_TYPE *typ = NULL; int ret = 0; const ASN1_PRIMITIVE_FUNCS *pf; ASN1_INTEGER **tint; pf = it->funcs; if(pf && pf->prim_c2i) return pf->prim_c2i(pval, cont, len, utype, free_cont, it); /* If ANY type clear type and set pointer to internal value */ if(it->utype == V_ASN1_ANY) { if(!*pval) { typ = ASN1_TYPE_new(); *pval = (ASN1_VALUE *)typ; } else typ = (ASN1_TYPE *)*pval; if(utype != typ->type) ASN1_TYPE_set(typ, utype, NULL); opval = pval; pval = (ASN1_VALUE **)&typ->value.ptr; } switch(utype) { case V_ASN1_OBJECT: if(!c2i_ASN1_OBJECT((ASN1_OBJECT **)pval, &cont, len)) goto err; break; case V_ASN1_NULL: if(len) { ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ASN1_R_NULL_IS_WRONG_LENGTH); goto err; } *pval = (ASN1_VALUE *)1; break; case V_ASN1_BOOLEAN: if(len != 1) { ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ASN1_R_BOOLEAN_IS_WRONG_LENGTH); goto err; } else { ASN1_BOOLEAN *tbool; tbool = (ASN1_BOOLEAN *)pval; *tbool = *cont; } break; case V_ASN1_BIT_STRING: if(!c2i_ASN1_BIT_STRING((ASN1_BIT_STRING **)pval, &cont, len)) goto err; break; case V_ASN1_INTEGER: case V_ASN1_NEG_INTEGER: case V_ASN1_ENUMERATED: case V_ASN1_NEG_ENUMERATED: tint = (ASN1_INTEGER **)pval; if(!c2i_ASN1_INTEGER(tint, &cont, len)) goto err; /* Fixup type to match the expected form */ (*tint)->type = utype | ((*tint)->type & V_ASN1_NEG); break; case V_ASN1_OCTET_STRING: case V_ASN1_NUMERICSTRING: case V_ASN1_PRINTABLESTRING: case V_ASN1_T61STRING: case V_ASN1_VIDEOTEXSTRING: case V_ASN1_IA5STRING: case V_ASN1_UTCTIME: case V_ASN1_GENERALIZEDTIME: case V_ASN1_GRAPHICSTRING: case V_ASN1_VISIBLESTRING: case V_ASN1_GENERALSTRING: case V_ASN1_UNIVERSALSTRING: case V_ASN1_BMPSTRING: case V_ASN1_UTF8STRING: case V_ASN1_OTHER: case V_ASN1_SET: case V_ASN1_SEQUENCE: default: /* All based on ASN1_STRING and handled the same */ if(!*pval) { stmp = ASN1_STRING_type_new(utype); if(!stmp) { ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ERR_R_MALLOC_FAILURE); goto err; } *pval = (ASN1_VALUE *)stmp; } else { stmp = (ASN1_STRING *)*pval; stmp->type = utype; } /* If we've already allocated a buffer use it */ if(*free_cont) { if(stmp->data) OPENSSL_free(stmp->data); stmp->data = cont; stmp->length = len; *free_cont = 0; } else { if(!ASN1_STRING_set(stmp, cont, len)) { ASN1err(ASN1_F_ASN1_D2I_EX_PRIMITIVE, ERR_R_MALLOC_FAILURE); ASN1_STRING_free(stmp); *pval = NULL; goto err; } } break; } /* If ASN1_ANY and NULL type fix up value */ if(typ && utype==V_ASN1_NULL) typ->value.ptr = NULL; ret = 1; err: if(!ret) { ASN1_TYPE_free(typ); if (opval) *opval = NULL; } return ret;}/* This function finds the end of an ASN1 structure when passed its maximum * length, whether it is indefinite length and a pointer to the content. * This is more efficient than calling asn1_collect because it does not * recurse on each indefinite length header. */static int asn1_find_end(unsigned char **in, long len, char inf) { int expected_eoc; long plen; unsigned char *p = *in, *q; /* If not indefinite length constructed just add length */ if (inf == 0) { *in += len; return 1; } expected_eoc = 1; /* Indefinite length constructed form. Find the end when enough EOCs * are found. If more indefinite length constructed headers * are encountered increment the expected eoc count otherwise justi * skip to the end of the data. */ while (len > 0) { if(asn1_check_eoc(&p, len)) { expected_eoc--; if (expected_eoc == 0) break; len -= 2; continue; } q = p; /* Just read in a header: only care about the length */ if(!asn1_check_tlen(&plen, NULL, NULL, &inf, NULL, &p, len, -1, 0, 0, NULL)) { ASN1err(ASN1_F_ASN1_FIND_END, ERR_R_NESTED_ASN1_ERROR); return 0; } if (inf) expected_eoc++; else p += plen; len -= p - q; } if (expected_eoc) { ASN1err(ASN1_F_ASN1_FIND_END, ASN1_R_MISSING_EOC); return 0; } *in = p; return 1; }/* This function collects the asn1 data from a constructred string * type into a buffer. The values of 'in' and 'len' should refer * to the contents of the constructed type and 'inf' should be set * if it is indefinite length. */static int asn1_collect(BUF_MEM *buf, unsigned char **in, long len, char inf, int tag, int aclass){ unsigned char *p, *q; long plen; char cst, ininf; p = *in; inf &= 1; while(len > 0) { q = p; /* Check for EOC */ if(asn1_check_eoc(&p, len)) { /* EOC is illegal outside indefinite length constructed form */ if(!inf) { ASN1err(ASN1_F_ASN1_COLLECT, ASN1_R_UNEXPECTED_EOC); return 0; } inf = 0; break; } if(!asn1_check_tlen(&plen, NULL, NULL, &ininf, &cst, &p, len, tag, aclass, 0, NULL)) { ASN1err(ASN1_F_ASN1_COLLECT, ERR_R_NESTED_ASN1_ERROR); return 0; } /* If indefinite length constructed update max length */ if(cst) {#ifdef OPENSSL_ALLOW_NESTED_ASN1_STRINGS if (!asn1_collect(buf, &p, plen, ininf, tag, aclass)) return 0;#else ASN1err(ASN1_F_ASN1_COLLECT, ASN1_R_NESTED_ASN1_STRING); return 0;#endif } else { if(plen && !collect_data(buf, &p, plen)) return 0; } len -= p - q; } if(inf) { ASN1err(ASN1_F_ASN1_COLLECT, ASN1_R_MISSING_EOC); return 0; } *in = p; return 1;}static int collect_data(BUF_MEM *buf, unsigned char **p, long plen){ int len; if(buf) { len = buf->length; if(!BUF_MEM_grow_clean(buf, len + plen)) { ASN1err(ASN1_F_COLLECT_DATA, ERR_R_MALLOC_FAILURE); return 0; } memcpy(buf->data + len, *p, plen); } *p += plen; return 1;}/* Check for ASN1 EOC and swallow it if found */static int asn1_check_eoc(unsigned char **in, long len){ unsigned char *p; if(len < 2) return 0; p = *in; if(!p[0] && !p[1]) { *in += 2; return 1; } return 0;}/* Check an ASN1 tag and length: a bit like ASN1_get_object * but it sets the length for indefinite length constructed * form, we don't know the exact length but we can set an * upper bound to the amount of data available minus the * header length just read. */static int asn1_check_tlen(long *olen, int *otag, unsigned char *oclass, char *inf, char *cst, unsigned char **in, long len, int exptag, int expclass, char opt, ASN1_TLC *ctx){ int i; int ptag, pclass; long plen; unsigned char *p, *q; p = *in; q = p; if(ctx && ctx->valid) { i = ctx->ret; plen = ctx->plen; pclass = ctx->pclass; ptag = ctx->ptag; p += ctx->hdrlen; } else { i = ASN1_get_object(&p, &plen, &ptag, &pclass, len); if(ctx) { ctx->ret = i; ctx->plen = plen; ctx->pclass = pclass; ctx->ptag = ptag; ctx->hdrlen = p - q; ctx->valid = 1; /* If definite length, and no error, length + * header can't exceed total amount of data available. */ if(!(i & 0x81) && ((plen + ctx->hdrlen) > len)) { ASN1err(ASN1_F_ASN1_CHECK_TLEN, ASN1_R_TOO_LONG); asn1_tlc_clear(ctx); return 0; } } } if(i & 0x80) { ASN1err(ASN1_F_ASN1_CHECK_TLEN, ASN1_R_BAD_OBJECT_HEADER); asn1_tlc_clear(ctx); return 0; } if(exptag >= 0) { if((exptag != ptag) || (expclass != pclass)) { /* If type is OPTIONAL, not an error, but indicate missing * type. */ if(opt) return -1; asn1_tlc_clear(ctx); ASN1err(ASN1_F_ASN1_CHECK_TLEN, ASN1_R_WRONG_TAG); return 0; } /* We have a tag and class match, so assume we are going to do something with it */ asn1_tlc_clear(ctx); } if(i & 1) plen = len - (p - q); if(inf) *inf = i & 1; if(cst) *cst = i & V_ASN1_CONSTRUCTED; if(olen) *olen = plen; if(oclass) *oclass = pclass; if(otag) *otag = ptag; *in = p; return 1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -