peass-ng/PEASS-ng · error · IOException

malformed BMPString encoding encountered

Error message

malformed BMPString encoding encountered

What it means

GetBmpCharBuffer requires BMPString contents to be an even number of bytes, since each character is encoded as 2 bytes (UCS-2). An odd remaining byte count means the encoding is malformed, so an IOException is thrown.

Source

Thrown at winPEAS/winPEASexe/winPEAS/3rdParty/BouncyCastle/asn1/Asn1InputStream.cs:334

                return defIn.ToArray();
            }

            byte[] buf = tmpBuffers[len];
            if (buf == null)
            {
                buf = tmpBuffers[len] = new byte[len];
            }

            defIn.ReadAllIntoByteArray(buf);

            return buf;
        }

        private static char[] GetBmpCharBuffer(DefiniteLengthInputStream defIn)
        {
            int remainingBytes = defIn.Remaining;
            if (0 != (remainingBytes & 1))
                throw new IOException("malformed BMPString encoding encountered");

            char[] str = new char[remainingBytes / 2];
            int stringPos = 0;

            byte[] buf = new byte[8];
            while (remainingBytes >= 8)
            {
                if (Streams.ReadFully(defIn, buf, 0, 8) != 8)
                    throw new EndOfStreamException("EOF encountered in middle of BMPString");

                str[stringPos] = (char)((buf[0] << 8) | (buf[1] & 0xFF));
                str[stringPos + 1] = (char)((buf[2] << 8) | (buf[3] & 0xFF));
                str[stringPos + 2] = (char)((buf[4] << 8) | (buf[5] & 0xFF));
                str[stringPos + 3] = (char)((buf[6] << 8) | (buf[7] & 0xFF));
                stringPos += 4;
                remainingBytes -= 8;
            }
            if (remainingBytes > 0)

View on GitHub (pinned to 53fb989abc)

Solutions

  1. Verify the DER encoding: BMPString length field must be even and match the actual byte count
  2. Re-encode the string with a correct encoder (DerBmpString) instead of manual byte assembly
  3. Check for bit-level corruption in the source data; re-obtain from a trusted source
  4. Catch IOException and report the specific certificate/field as malformed

Example fix

// before
byte[] bad = Encoding.Unicode.GetBytes("CN"); // truncated by 1 byte upstream
// after
Asn1Object bmp = new DerBmpString("CN"); // let the library encode
byte[] der = bmp.GetDerEncoded();
Defensive patterns

Strategy: validation

Validate before calling

static bool BmpStringLengthIsEven(byte[] der)
{
    // locate a primitive BMPString (tag 0x1E) and check its content length parity
    for (int i = 0; i + 1 < der.Length; i++)
    {
        if (der[i] == 0x1e)
        {
            int lb = der[i + 1];
            return (lb & 1) == 0;
        }
    }
    return true; // no BMPString found
}

Try / catch

try { Asn1Object o = Asn1Object.FromByteArray(data); }
catch (IOException ex) when (ex.Message.Contains("BMPString"))
{
    // malformed BMPString encoding
}

Prevention

When it happens

Trigger: Parsing a primitive BMPString (tag 0x1E) whose definite length is odd, e.g. corrupt DER or hand-assembled bytes with a wrong length field.

Common situations: Corrupted certificates where the BMPString (often used in certificate subject/issuer fields) length byte was damaged; buggy encoders writing byte-count instead of char-count; manually constructed ASN.1 test data.

Understand the failure class

Related errors


AI-assisted analysis of peass-ng/PEASS-ng@53fb989abc (2026-09-02). Data as JSON: /api/errors/0c75f6691ace095b. Report an issue: GitHub.