Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support indefinite length BER encodings in PKCS #7 #1380

Merged
merged 5 commits into from
Feb 22, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ then
enable_aeskeywrap=yes
enable_x963kdf=yes
enable_scrypt=yes
enable_indef=yes

AM_CFLAGS="-DHAVE_AES_DECRYPT $AM_CFLAGS"
fi
Expand Down Expand Up @@ -2662,6 +2663,19 @@ fi
AM_CONDITIONAL([BUILD_SRP], [test "x$ENABLED_SRP" = "xyes"])


# Indefinite length encoded BER message support
AC_ARG_ENABLE([indef],
[AS_HELP_STRING([--enable-indef],[Enable parsing of indefinite length encoded msgs (default: disabled)])],
[ ENABLED_BER_INDEF=$enableval ],
[ ENABLED_BER_INDEF=no ]
)

if test "x$ENABLED_BER_INDEF" = "xyes"
then
AM_CFLAGS="$AM_CFLAGS -DASN_BER_TO_DER"
fi



# Small Stack
AC_ARG_ENABLE([smallstack],
Expand Down Expand Up @@ -4247,6 +4261,7 @@ echo " * SIGNAL: $ENABLED_SIGNAL"
echo " * ERROR_STRINGS: $ENABLED_ERROR_STRINGS"
echo " * DTLS: $ENABLED_DTLS"
echo " * SCTP: $ENABLED_SCTP"
echo " * Indefinite Length: $ENABLED_BER_INDEF"
echo " * Multicast: $ENABLED_MCAST"
echo " * Old TLS Versions: $ENABLED_OLD_TLS"
echo " * SSL version 3.0: $ENABLED_SSLV3"
Expand Down
205 changes: 205 additions & 0 deletions wolfcrypt/src/asn.c
Original file line number Diff line number Diff line change
Expand Up @@ -786,6 +786,211 @@ static word32 SetBitString(word32 len, byte unusedBits, byte* output)
}
#endif /* !NO_RSA || HAVE_ECC || HAVE_ED25519 */

#ifdef ASN_BER_TO_DER
/* Convert a BER encoding with indefinite length items to DER.
*
* ber BER encoded data.
* berSz Length of BER encoded data.
* der Buffer to hold DER encoded version of data.
* NULL indicates only the length is required.
* derSz The size of the buffer to hold the DER encoded data.
* Will be set if der is NULL, otherwise the value is checked as der is
* filled.
* returns ASN_PARSE_E if the BER data is invalid and BAD_FUNC_ARG if ber or
* derSz are NULL.
*/
int wc_BerToDer(const byte* ber, word32 berSz, byte* der, word32* derSz)
{
int ret;
word32 i, j, k;
int len, l;
int indef;
int depth = 0;
byte type;
word32 cnt, sz;
word32 outSz;
byte lenBytes[4];

if (ber == NULL || derSz == NULL)
return BAD_FUNC_ARG;

outSz = *derSz;

for (i = 0, j = 0; i < berSz; ) {
/* Check that there is data for an ASN item to parse. */
if (i + 2 > berSz)
return ASN_PARSE_E;

/* End Of Content (EOC) mark end of indefinite length items.
* EOCs are not encoded in DER.
* Keep track of no. indefinite length items that have not been
* terminated in depth.
*/
if (ber[i] == 0 && ber[i+1] == 0) {
if (depth == 0)
break;
if (--depth == 0)
break;

i += 2;
continue;
}

/* Indefinite length is encoded as: 0x80 */
type = ber[i];
indef = ber[i+1] == ASN_INDEF_LENGTH;
if (indef && (type & 0xC0) == 0 &&
ber[i] != (ASN_SEQUENCE | ASN_CONSTRUCTED) &&
ber[i] != (ASN_SET | ASN_CONSTRUCTED)) {
/* Indefinite length OCTET STRING or other simple type.
* Put all the data into one entry.
*/

/* Type no longer constructed. */
type &= ~ASN_CONSTRUCTED;
if (der != NULL) {
/* Ensure space for type. */
if (j + 1 >= outSz)
return BUFFER_E;
der[j] = type;
}
i++; j++;
/* Skip indefinite length. */
i++;

/* There must be further ASN1 items to combine. */
if (i + 2 > berSz)
return ASN_PARSE_E;

/* Calculate length of combined data. */
len = 0;
k = i;
while (ber[k] != 0x00) {
/* Each ASN item must be the same type as the constructed. */
if (ber[k] != type)
return ASN_PARSE_E;
k++;

ret = GetLength(ber, &k, &l, berSz);
if (ret < 0)
return ASN_PARSE_E;
k += l;
len += l;

/* Must at least have terminating EOC. */
if (k + 2 > berSz)
return ASN_PARSE_E;
}
/* Ensure a valid EOC ASN item. */
if (ber[k+1] != 0x00)
return ASN_PARSE_E;

if (der == NULL) {
/* Add length of ASN item length encoding and data. */
j += SetLength(len, lenBytes);
j += len;
}
else {
/* Check space for encoded length. */
if (SetLength(len, lenBytes) > outSz - j)
return BUFFER_E;
/* Encode new length. */
j += SetLength(len, der + j);

/* Encode data in single item. */
k = i;
while (ber[k] != 0x00) {
/* Skip ASN type. */
k++;

/* Find length of data in ASN item. */
ret = GetLength(ber, &k, &l, berSz);
if (ret < 0)
return ASN_PARSE_E;

/* Ensure space for data and copy in. */
if (j + l > outSz)
return BUFFER_E;
XMEMCPY(der + j, ber + k, l);
k += l; j += l;
}
}
/* Continue conversion after EOC. */
i = k + 2;

continue;
}

if (der != NULL) {
/* Ensure space for type and at least one byte of length. */
if (j + 1 >= outSz)
return BUFFER_E;
/* Put in type. */
der[j] = ber[i];
}
i++; j++;

if (indef) {
/* Skip indefinite length. */
i++;
/* Calculate the size of the data inside constructed. */
ret = wc_BerToDer(ber + i, berSz - i, NULL, &sz);
if (ret != LENGTH_ONLY_E)
return ret;

if (der != NULL) {
/* Ensure space for encoded length. */
if (SetLength(sz, lenBytes) > outSz - j)
return BUFFER_E;
/* Encode real length. */
j += SetLength(sz, der + j);
}
else {
/* Add size of encoded length. */
j += SetLength(sz, lenBytes);
}

/* Another EOC to find. */
depth++;
}
else {
/* Get the size of the encode length and length value. */
cnt = i;
ret = GetLength(ber, &cnt, &len, berSz);
if (ret < 0)
return ASN_PARSE_E;
cnt -= i;

/* Check there is enough data to copy out. */
if (i + cnt + len > berSz)
return ASN_PARSE_E;

if (der != NULL) {
/* Ensure space in DER buffer. */
if (j + cnt + len > outSz)
return BUFFER_E;
/* Copy length and data into DER buffer. */
XMEMCPY(der + j, ber + i, cnt + len);
}
/* Continue conversion after this ASN item. */
i += cnt + len;
j += cnt + len;
}
}

if (depth >= 1)
return ASN_PARSE_E;

/* Return length if no buffer to write to. */
if (der == NULL) {
*derSz = j;
return LENGTH_ONLY_E;
}

return 0;
}
#endif

#if defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_KEY_GEN)

#if (!defined(NO_RSA) && !defined(HAVE_USER_RSA)) || \
Expand Down
3 changes: 3 additions & 0 deletions wolfcrypt/src/error.c
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,9 @@ const char* wc_GetErrorString(int error)
case PRIME_GEN_E:
return "Unable to find a prime for RSA key";

case BER_INDEF_E:
return "Unable to decode an indefinite length encoded message";

default:
return "unknown error number";

Expand Down
Loading