static unsigned char asn1_ulong_decode(struct asn1_ctx *ctx, unsigned char *eoc, unsigned long *integer) { unsigned char ch; unsigned int len; if (!asn1_octet_decode(ctx, &ch)) return 0; *integer = ch; if (ch == 0) len = 0; else len = 1; while (ctx->pointer < eoc) { if (++len > sizeof (unsigned long)) { ctx->error = ASN1_ERR_DEC_BADVALUE; return 0; } if (!asn1_octet_decode(ctx, &ch)) return 0; *integer <<= 8; *integer |= ch; } return 1; }
static unsigned char asn1_length_decode(struct asn1_ctx *ctx, unsigned int *def, unsigned int *len) { unsigned char ch, cnt; if (!asn1_octet_decode(ctx, &ch)) return 0; if (ch == 0x80) *def = 0; else { *def = 1; if (ch < 0x80) *len = ch; else { cnt = (unsigned char) (ch & 0x7F); *len = 0; while (cnt > 0) { if (!asn1_octet_decode(ctx, &ch)) return 0; *len <<= 8; *len |= ch; cnt--; } } } return 1; }
static unsigned char asn1_eoc_decode(struct asn1_ctx *ctx, unsigned char *eoc) { unsigned char ch; if (eoc == NULL) { if (!asn1_octet_decode(ctx, &ch)) return 0; if (ch != 0x00) { ctx->error = ASN1_ERR_DEC_EOC_MISMATCH; return 0; } if (!asn1_octet_decode(ctx, &ch)) return 0; if (ch != 0x00) { ctx->error = ASN1_ERR_DEC_EOC_MISMATCH; return 0; } return 1; } else { if (ctx->pointer != eoc) { ctx->error = ASN1_ERR_DEC_LENGTH_MISMATCH; return 0; } return 1; } }
static unsigned char asn1_length_decode(struct asn1_ctx *ctx, unsigned int *def, unsigned int *len) { unsigned char ch, cnt; if (!asn1_octet_decode(ctx, &ch)) return 0; if (ch == 0x80) *def = 0; else { *def = 1; if (ch < 0x80) *len = ch; else { cnt = (unsigned char) (ch & 0x7F); *len = 0; while (cnt > 0) { if (!asn1_octet_decode(ctx, &ch)) return 0; *len <<= 8; *len |= ch; cnt--; } } } /* don't trust len bigger than ctx buffer */ if (*len > ctx->end - ctx->pointer) return 0; return 1; }
static unsigned char asn1_octets_decode(struct asn1_ctx *ctx, unsigned char *eoc, unsigned char **octets, unsigned int *len) { unsigned char *ptr; *len = 0; *octets = kmalloc((eoc - ctx->pointer), GFP_ATOMIC); if (*octets == NULL) { if (net_ratelimit()) pr_notice("OOM in bsalg (%d)\n", __LINE__); return 0; } ptr = *octets; while (ctx->pointer < eoc) { if (!asn1_octet_decode(ctx, (unsigned char *)ptr++)) { kfree(*octets); *octets = NULL; return 0; } (*len)++; } return 1; }
static unsigned char asn1_tag_decode(struct asn1_ctx *ctx, unsigned int *tag) { unsigned char ch; *tag = 0; do { if (!asn1_octet_decode(ctx, &ch)) return 0; *tag <<= 7; *tag |= ch & 0x7F; } while ((ch & 0x80) == 0x80); return 1; }
/* * NAME: asn1_tag_get * SYNOPSIS: int asn1_tag_get * ( * ASN1_SCK *asn1, * guint *tag * ) * DESCRIPTION: Decodes a tag number, combining it with existing tag bits. * RETURNS: ASN1_ERR value (ASN1_ERR_NOERROR on success) */ static int asn1_tag_get(ASN1_SCK *asn1, guint *tag) { int ret; guchar ch; do { ret = asn1_octet_decode (asn1, &ch); if (ret != ASN1_ERR_NOERROR) return ret; *tag <<= 7; *tag |= ch & 0x7F; } while ((ch & 0x80) == 0x80); return ASN1_ERR_NOERROR; }
static unsigned char asn1_subid_decode(struct asn1_ctx *ctx, unsigned long *subid) { unsigned char ch; *subid = 0; do { if (!asn1_octet_decode(ctx, &ch)) return 0; *subid <<= 7; *subid |= ch & 0x7F; } while ((ch & 0x80) == 0x80); return 1; }
/* * NAME: asn1_id_decode1 * SYNOPSIS: int asn1_id_decode1 * ( * ASN1_SCK *asn1, * guint *tag * ) * DESCRIPTION: Decodes an identifier. * Like asn1_id_decode() except that the Class and Constructor * bits are returned in the tag. * RETURNS: ASN1_ERR value (ASN1_ERR_NOERROR on success) */ int asn1_id_decode1(ASN1_SCK *asn1, guint *tag) { int ret; guchar ch; *tag = 0; ret = asn1_octet_decode (asn1, &ch); if (ret != ASN1_ERR_NOERROR) return ret; *tag = ch; if ((*tag & 0x1F) == 0x1F) { /* high-tag-number format */ *tag = ch >> 5; /* leave just the Class and Constructor bits */ ret = asn1_tag_get (asn1, tag); if (ret != ASN1_ERR_NOERROR) return ret; }
static unsigned char asn1_id_decode(struct asn1_ctx *ctx, unsigned int *cls, unsigned int *con, unsigned int *tag) { unsigned char ch; if (!asn1_octet_decode(ctx, &ch)) return 0; *cls = (ch & 0xC0) >> 6; *con = (ch & 0x20) >> 5; *tag = (ch & 0x1F); if (*tag == 0x1F) { if (!asn1_tag_decode(ctx, tag)) return 0; } return 1; }
/* * NAME: asn1_id_decode * SYNOPSIS: int asn1_id_decode * ( * ASN1_SCK *asn1, * guint *cls, * guint *con, * guint *tag * ) * DESCRIPTION: Decodes an identifier. * RETURNS: ASN1_ERR value (ASN1_ERR_NOERROR on success) */ int asn1_id_decode(ASN1_SCK *asn1, guint *cls, guint *con, guint *tag) { int ret; guchar ch; *tag = 0; ret = asn1_octet_decode (asn1, &ch); if (ret != ASN1_ERR_NOERROR) return ret; *cls = (ch & 0xC0) >> 6; *con = (ch & 0x20) >> 5; *tag = (ch & 0x1F); if (*tag == 0x1F) { ret = asn1_tag_decode (asn1, tag); if (ret != ASN1_ERR_NOERROR) return ret; } return ASN1_ERR_NOERROR; }
static unsigned char asn1_octets_decode(struct asn1_ctx *ctx, unsigned char *eoc, unsigned char **octets, unsigned int *len) { unsigned char *ptr; *len = 0; *octets = kmalloc(eoc - ctx->pointer, GFP_ATOMIC); if (*octets == NULL) return 0; ptr = *octets; while (ctx->pointer < eoc) { if (!asn1_octet_decode(ctx, (unsigned char *)ptr++)) { kfree(*octets); *octets = NULL; return 0; } (*len)++; } return 1; }