提交 e128f891 编写于 作者: A Andy Polyakov

asn1/x_long.c: remove conditions in inner loops and dependency on BN.

Reviewed-by: NRich Salz <rsalz@openssl.org>
Reviewed-by: NRichard Levitte <levitte@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/3152)
上级 3de47fb2
...@@ -10,7 +10,6 @@ ...@@ -10,7 +10,6 @@
#include <stdio.h> #include <stdio.h>
#include "internal/cryptlib.h" #include "internal/cryptlib.h"
#include <openssl/asn1t.h> #include <openssl/asn1t.h>
#include <openssl/bn.h>
/* /*
* Custom primitive type for long handling. This converts between an * Custom primitive type for long handling. This converts between an
...@@ -56,11 +55,36 @@ static void long_free(ASN1_VALUE **pval, const ASN1_ITEM *it) ...@@ -56,11 +55,36 @@ static void long_free(ASN1_VALUE **pval, const ASN1_ITEM *it)
*(long *)pval = it->size; *(long *)pval = it->size;
} }
/*
* Originally BN_num_bits_word was called to perform this operation, but
* trouble is that there is no guarantee that sizeof(long) equals to
* sizeof(BN_ULONG). BN_ULONG is a configurable type that can be as wide
* as long, but also double or half...
*/
static int num_bits_ulong(unsigned long value)
{
size_t i;
unsigned long ret = 0;
/*
* It is argued that *on average* constant counter loop performs
* not worse [if not better] than one with conditional break or
* mask-n-table-lookup-style, because of branch misprediction
* penalties.
*/
for (i = 0; i < sizeof(value) * 8; i++) {
ret += (value != 0);
value >>= 1;
}
return (int)ret;
}
static int long_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype, static int long_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype,
const ASN1_ITEM *it) const ASN1_ITEM *it)
{ {
long ltmp; long ltmp;
unsigned long utmp; unsigned long utmp, sign;
int clen, pad, i; int clen, pad, i;
/* this exists to bypass broken gcc optimization */ /* this exists to bypass broken gcc optimization */
char *cp = (char *)pval; char *cp = (char *)pval;
...@@ -75,11 +99,14 @@ static int long_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype, ...@@ -75,11 +99,14 @@ static int long_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype,
* cleanly handle the padding if only the MSB of the leading octet is * cleanly handle the padding if only the MSB of the leading octet is
* set. * set.
*/ */
if (ltmp < 0) if (ltmp < 0) {
sign = 0xff;
utmp = 0 - (unsigned long)ltmp - 1; utmp = 0 - (unsigned long)ltmp - 1;
else } else {
sign = 0;
utmp = ltmp; utmp = ltmp;
clen = BN_num_bits_word(utmp); }
clen = num_bits_ulong(utmp);
/* If MSB of leading octet set we need to pad */ /* If MSB of leading octet set we need to pad */
if (!(clen & 0x7)) if (!(clen & 0x7))
pad = 1; pad = 1;
...@@ -89,13 +116,11 @@ static int long_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype, ...@@ -89,13 +116,11 @@ static int long_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype,
/* Convert number of bits to number of octets */ /* Convert number of bits to number of octets */
clen = (clen + 7) >> 3; clen = (clen + 7) >> 3;
if (cont) { if (cont != NULL) {
if (pad) if (pad)
*cont++ = (ltmp < 0) ? 0xff : 0; *cont++ = (unsigned char)sign;
for (i = clen - 1; i >= 0; i--) { for (i = clen - 1; i >= 0; i--) {
cont[i] = (unsigned char)(utmp & 0xff); cont[i] = (unsigned char)(utmp ^ sign);
if (ltmp < 0)
cont[i] ^= 0xff;
utmp >>= 8; utmp >>= 8;
} }
} }
...@@ -105,9 +130,9 @@ static int long_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype, ...@@ -105,9 +130,9 @@ static int long_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype,
static int long_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len, static int long_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
int utype, char *free_cont, const ASN1_ITEM *it) int utype, char *free_cont, const ASN1_ITEM *it)
{ {
int neg = -1, i; int i;
long ltmp; long ltmp;
unsigned long utmp = 0; unsigned long utmp = 0, sign = 0x100;
char *cp = (char *)pval; char *cp = (char *)pval;
if (len > 1) { if (len > 1) {
...@@ -120,12 +145,12 @@ static int long_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len, ...@@ -120,12 +145,12 @@ static int long_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
case 0xff: case 0xff:
cont++; cont++;
len--; len--;
neg = 0x80; sign = 0xff;
break; break;
case 0: case 0:
cont++; cont++;
len--; len--;
neg = 0; sign = 0;
break; break;
} }
} }
...@@ -133,33 +158,29 @@ static int long_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len, ...@@ -133,33 +158,29 @@ static int long_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
ASN1err(ASN1_F_LONG_C2I, ASN1_R_INTEGER_TOO_LARGE_FOR_LONG); ASN1err(ASN1_F_LONG_C2I, ASN1_R_INTEGER_TOO_LARGE_FOR_LONG);
return 0; return 0;
} }
if (neg == -1) {
if (sign == 0x100) {
/* Is it negative? */ /* Is it negative? */
if (len && (cont[0] & 0x80)) if (len && (cont[0] & 0x80))
neg = 1; sign = 0xff;
else else
neg = 0; sign = 0;
} else if (neg == (cont[0] & 0x80)) { } else if (((sign ^ cont[0]) & 0x80) == 0) { /* same sign bit? */
ASN1err(ASN1_F_LONG_C2I, ASN1_R_ILLEGAL_PADDING); ASN1err(ASN1_F_LONG_C2I, ASN1_R_ILLEGAL_PADDING);
return 0; return 0;
} }
utmp = 0; utmp = 0;
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
utmp <<= 8; utmp <<= 8;
if (neg) utmp |= cont[i] ^ sign;
utmp |= cont[i] ^ 0xff;
else
utmp |= cont[i];
} }
ltmp = (long)utmp; ltmp = (long)utmp;
if (ltmp < 0) { if (ltmp < 0) {
ASN1err(ASN1_F_LONG_C2I, ASN1_R_INTEGER_TOO_LARGE_FOR_LONG); ASN1err(ASN1_F_LONG_C2I, ASN1_R_INTEGER_TOO_LARGE_FOR_LONG);
return 0; return 0;
} }
if (neg) { if (sign)
ltmp = -ltmp; ltmp = -ltmp - 1;
ltmp--;
}
if (ltmp == it->size) { if (ltmp == it->size) {
ASN1err(ASN1_F_LONG_C2I, ASN1_R_INTEGER_TOO_LARGE_FOR_LONG); ASN1err(ASN1_F_LONG_C2I, ASN1_R_INTEGER_TOO_LARGE_FOR_LONG);
return 0; return 0;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册