diff options
-rw-r--r-- | source4/libcli/util/asn1.c | 44 |
1 files changed, 40 insertions, 4 deletions
diff --git a/source4/libcli/util/asn1.c b/source4/libcli/util/asn1.c index 7025808a1e..7e313bcd4a 100644 --- a/source4/libcli/util/asn1.c +++ b/source4/libcli/util/asn1.c @@ -107,23 +107,59 @@ BOOL asn1_pop_tag(ASN1_DATA *data) return True; } -static void push_int_bigendian(ASN1_DATA *data, int i) +/* "i" is the one's complement representation, as is the normal result of an + * implicit signed->unsigned conversion */ + +static void push_int_bigendian(ASN1_DATA *data, unsigned int i, BOOL negative) { uint8_t lowest = i & 0xFF; i = i >> 8; if (i != 0) - push_int_bigendian(data, i); + push_int_bigendian(data, i, negative); + + if (data->nesting->start+1 == data->ofs) { + + /* We did not write anything yet, looking at the highest + * valued byte */ + + if (negative) { + /* Don't write leading 0xff's */ + if (lowest == 0xFF) + return; + + if ((lowest & 0x80) == 0) { + /* The only exception for a leading 0xff is if + * the highest bit is 0, which would indicate + * a positive value */ + asn1_write_uint8(data, 0xff); + } + } else { + if (lowest & 0x80) { + /* The highest bit of a positive integer is 1, + * this would indicate a negative number. Push + * a 0 to indicate a positive one */ + asn1_write_uint8(data, 0); + } + } + } asn1_write_uint8(data, lowest); } - /* write an integer */ BOOL asn1_write_Integer(ASN1_DATA *data, int i) { if (!asn1_push_tag(data, ASN1_INTEGER)) return False; - push_int_bigendian(data, i); + if (i == -1) { + /* -1 is special as it consists of all-0xff bytes. In + push_int_bigendian this is the only case that is not + properly handled, as all 0xff bytes would be handled as + leading ones to be ignored. */ + asn1_write_uint8(data, 0xff); + } else { + push_int_bigendian(data, i, i<0); + } return asn1_pop_tag(data); } |