diff options
author | Pauli <paul.dale@oracle.com> | 2017-07-12 08:54:14 +1000 |
---|---|---|
committer | Pauli <paul.dale@oracle.com> | 2017-07-14 07:32:58 +1000 |
commit | a9a157e74a0c6a886e593426f263f3d7359497b9 (patch) | |
tree | 8b631dfca3133152a5fc5e359b1f5442a7035130 /crypto | |
parent | 9e206ce5f80172136b503ca23fbd8e53b78eb4b7 (diff) |
Avoid having an unsigned integer decrement below zero.
Reviewed-by: Andy Polyakov <appro@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/3912)
Diffstat (limited to 'crypto')
-rw-r--r-- | crypto/asn1/asn1_lib.c | 29 |
1 files changed, 18 insertions, 11 deletions
diff --git a/crypto/asn1/asn1_lib.c b/crypto/asn1/asn1_lib.c index 8ca53b4ce4..3f5c12d50b 100644 --- a/crypto/asn1/asn1_lib.c +++ b/crypto/asn1/asn1_lib.c @@ -102,41 +102,48 @@ int ASN1_get_object(const unsigned char **pp, long *plength, int *ptag, return (0x80); } +/* + * Decode a length field. + * The short form is a single byte defining a length 0 - 127. + * The long form is a byte 0 - 127 with the top bit set and this indicates + * the number of following octets that contain the length. These octets + * are stored most significant digit first. + */ static int asn1_get_length(const unsigned char **pp, int *inf, long *rl, long max) { const unsigned char *p = *pp; unsigned long ret = 0; - unsigned long i; + int i; if (max-- < 1) return 0; if (*p == 0x80) { *inf = 1; - ret = 0; p++; } else { *inf = 0; i = *p & 0x7f; - if (*(p++) & 0x80) { - if (max < (long)i + 1) + if (*p++ & 0x80) { + if (max < i + 1) return 0; /* Skip leading zeroes */ - while (i && *p == 0) { + while (i > 0 && *p == 0) { p++; i--; } - if (i > sizeof(long)) + if (i > (int)sizeof(long)) return 0; - while (i-- > 0) { - ret <<= 8L; - ret |= *(p++); + while (i > 0) { + ret <<= 8; + ret |= *p++; + i--; } + if (ret > LONG_MAX) + return 0; } else ret = i; } - if (ret > LONG_MAX) - return 0; *pp = p; *rl = (long)ret; return 1; |