/* * asn1_decode_maybe_unsigned * * This is needed because older releases of MIT krb5 have signed * sequence numbers. We want to accept both signed and unsigned * sequence numbers, in the range -2^31..2^32-1, mapping negative * numbers into their positive equivalents in the same way that C's * normal integer conversions do, i.e., would preserve bits on a * two's-complement architecture. */ asn1_error_code asn1_decode_maybe_unsigned(asn1buf *buf, unsigned long *val) { setup(); asn1_octet o; unsigned long n, bitsremain; unsigned int i; tag(ASN1_INTEGER); o = 0; n = 0; bitsremain = ~0UL; for (i = 0; i < length; i++) { /* Accounts for u_long width not being a multiple of 8. */ if (bitsremain < 0xff) return ASN1_OVERFLOW; retval = asn1buf_remove_octet(buf, &o); if (retval) return retval; if (bitsremain == ~0UL) { if (i == 0) n = (o & 0x80) ? ~0UL : 0UL; /* grab sign bit */ /* * Skip leading zero or 0xFF octets to humor non-compliant encoders. */ if (n == 0 && o == 0) continue; if (n == ~0UL && o == 0xff) continue; } n = (n << 8) | o; bitsremain >>= 8; } *val = n; cleanup(); }
asn1_error_code asn1_decode_integer(asn1buf *buf, long int *val) { setup(); asn1_octet o; long n = 0; /* initialize to keep gcc happy */ unsigned int i; tag(ASN1_INTEGER); for (i = 0; i < length; i++) { retval = asn1buf_remove_octet(buf, &o); if (retval) return retval; if (!i) { n = (0x80 & o) ? -1 : 0; /* grab sign bit */ if (n < 0 && length > sizeof (long)) return ASN1_OVERFLOW; else if (length > sizeof (long) + 1) /* allow extra octet for positive */ return ASN1_OVERFLOW; } n = (n << 8) | o; } *val = n; cleanup(); }
asn1_error_code asn1_decode_boolean(asn1buf *buf, unsigned *val) { setup(); asn1_octet bval; tag(ASN1_BOOLEAN); retval = asn1buf_remove_octet(buf, &bval); if (retval) return retval; *val = (bval != 0x00); cleanup(); }
asn1_error_code asn1_decode_unsigned_integer(asn1buf *buf, long unsigned int *val) { setup(); asn1_octet o; unsigned long n; unsigned int i; tag(ASN1_INTEGER); for (i = 0, n = 0; i < length; i++) { retval = asn1buf_remove_octet(buf, &o); if (retval) return retval; if (!i) { if (0x80 & o) return ASN1_OVERFLOW; else if (length > sizeof (long) + 1) return ASN1_OVERFLOW; } n = (n << 8) | o; } *val = n; cleanup(); }
asn1_error_code asn1_get_tag_2(asn1buf *buf, taginfo *t) { asn1_error_code retval; if (buf == NULL || buf->base == NULL || buf->bound - buf->next + 1 <= 0) { t->tagnum = ASN1_TAGNUM_CEILING; /* emphatically not an EOC tag */ t->asn1class = UNIVERSAL; t->construction = PRIMITIVE; t->length = 0; t->indef = 0; return 0; } { /* asn1_get_id(buf, t) */ asn1_tagnum tn=0; asn1_octet o; #define ASN1_CLASS_MASK 0xC0 #define ASN1_CONSTRUCTION_MASK 0x20 #define ASN1_TAG_NUMBER_MASK 0x1F retval = asn1buf_remove_octet(buf,&o); if (retval) return retval; t->asn1class = (asn1_class)(o&ASN1_CLASS_MASK); t->construction = (asn1_construction)(o&ASN1_CONSTRUCTION_MASK); if ((o&ASN1_TAG_NUMBER_MASK) != ASN1_TAG_NUMBER_MASK) { /* low-tag-number form */ t->tagnum = (asn1_tagnum)(o&ASN1_TAG_NUMBER_MASK); } else { /* high-tag-number form */ do { retval = asn1buf_remove_octet(buf,&o); if (retval) return retval; tn = (tn<<7) + (asn1_tagnum)(o&0x7F); } while (o&0x80); t->tagnum = tn; } } { /* asn1_get_length(buf, t) */ asn1_octet o; t->indef = 0; retval = asn1buf_remove_octet(buf,&o); if (retval) return retval; if ((o&0x80) == 0) { t->length = (int)(o&0x7F); } else { int num; int len=0; for (num = (int)(o&0x7F); num>0; num--) { retval = asn1buf_remove_octet(buf,&o); if (retval) return retval; len = (len<<8) + (int)o; } if (len < 0) return ASN1_OVERRUN; if (!len) t->indef = 1; t->length = len; } } if (t->indef && t->construction != CONSTRUCTED) return ASN1_MISMATCH_INDEF; return 0; }