Esempio n. 1
0
        public CBORObject ReadForFirstByte(int firstbyte)
        {
            if (this.depth > 500)
            {
                throw new CBORException("Too deeply nested");
            }
            if (firstbyte < 0)
            {
                throw new CBORException("Premature end of data");
            }
            if (firstbyte == 0xff)
            {
                throw new CBORException("Unexpected break code encountered");
            }
            int        type       = (firstbyte >> 5) & 0x07;
            int        additional = firstbyte & 0x1f;
            long       uadditional;
            CBORObject fixedObject;

            if (this.options.Ctap2Canonical)
            {
                if (additional >= 0x1c)
                {
                    // NOTE: Includes stop byte and indefinite length data items
                    throw new CBORException("Invalid canonical CBOR encountered");
                }
                // Check if this represents a fixed object (NOTE: All fixed objects
                // comply with CTAP2 canonical CBOR).
                fixedObject = CBORObject.GetFixedObject(firstbyte);
                if (fixedObject != null)
                {
                    return(fixedObject);
                }
                if (type == 6)
                {
                    throw new CBORException("Tags not allowed in canonical CBOR");
                }
                uadditional = ReadDataLength(
                    this.stream,
                    firstbyte,
                    type,
                    type == 7);
                if (type == 0)
                {
                    return((uadditional >> 63) != 0 ?
                           CBORObject.FromObject(ToUnsignedEInteger(uadditional)) :
                           CBORObject.FromObject(uadditional));
                }
                else if (type == 1)
                {
                    return((uadditional >> 63) != 0 ? CBORObject.FromObject(
                               ToUnsignedEInteger(uadditional).Add(1).Negate()) :
                           CBORObject.FromObject((-uadditional) - 1L));
                }
                else if (type == 7)
                {
                    if (additional < 24)
                    {
                        return(CBORObject.FromSimpleValue(additional));
                    }
                    else if (additional == 24 && uadditional < 32)
                    {
                        throw new CBORException("Invalid simple value encoding");
                    }
                    else if (additional == 24)
                    {
                        return(CBORObject.FromSimpleValue((int)uadditional));
                    }
                    else if (additional == 25)
                    {
                        return(CBORObject.FromFloatingPointBits(uadditional, 2));
                    }
                    else if (additional == 26)
                    {
                        return(CBORObject.FromFloatingPointBits(uadditional, 4));
                    }
                    else if (additional == 27)
                    {
                        return(CBORObject.FromFloatingPointBits(uadditional, 8));
                    }
                }
                else if (type >= 2 && type <= 5)
                {
                    return(this.ReadStringArrayMap(type, uadditional));
                }
                throw new CBORException("Unexpected data encountered");
            }
            int expectedLength = CBORObject.GetExpectedLength(firstbyte);

            // Data checks
            if (expectedLength == -1)
            {
                // if the head byte is invalid
                throw new CBORException("Unexpected data encountered");
            }
            // Check if this represents a fixed object
            fixedObject = CBORObject.GetFixedObject(firstbyte);
            if (fixedObject != null)
            {
                return(fixedObject);
            }
            // Read fixed-length data
            byte[] data = null;
            if (expectedLength != 0)
            {
                data = new byte[expectedLength];
                // include the first byte because GetFixedLengthObject
                // will assume it exists for some head bytes
                data[0] = unchecked ((byte)firstbyte);
                if (expectedLength > 1 &&
                    this.stream.Read(data, 1, expectedLength - 1) != expectedLength
                    - 1)
                {
                    throw new CBORException("Premature end of data");
                }
                CBORObject cbor = CBORObject.GetFixedLengthObject(firstbyte, data);
                if (this.stringRefs != null && (type == 2 || type == 3))
                {
                    this.stringRefs.AddStringIfNeeded(cbor, expectedLength - 1);
                }
                return(cbor);
            }
            if (additional == 31)
            {
                // Indefinite-length for major types 2 to 5 (other major
                // types were already handled in the call to
                // GetFixedLengthObject).
                switch (type)
                {
                case 2: {
                    // Streaming byte string
                    using (var ms = new MemoryStream()) {
                        // Requires same type as this one
                        while (true)
                        {
                            int nextByte = this.stream.ReadByte();
                            if (nextByte == 0xff)
                            {
                                // break if the "break" code was read
                                break;
                            }
                            long len = ReadDataLength(this.stream, nextByte, 2);
                            if ((len >> 63) != 0 || len > Int32.MaxValue)
                            {
                                throw new CBORException("Length" + ToUnsignedEInteger(len)
                                                        +
                                                        " is bigger than supported ");
                            }
                            if (nextByte != 0x40)
                            {
                                // NOTE: 0x40 means the empty byte string
                                ReadByteData(this.stream, len, ms);
                            }
                        }
                        if (ms.Position > Int32.MaxValue)
                        {
                            throw new
                                  CBORException("Length of bytes to be streamed is bigger" +
                                                "\u0020than supported ");
                        }
                        data = ms.ToArray();
                        return(CBORObject.FromRaw(data));
                    }
                }

                case 3: {
                    // Streaming text string
                    var builder = new StringBuilder();
                    while (true)
                    {
                        int nextByte = this.stream.ReadByte();
                        if (nextByte == 0xff)
                        {
                            // break if the "break" code was read
                            break;
                        }
                        long len = ReadDataLength(this.stream, nextByte, 3);
                        if ((len >> 63) != 0 || len > Int32.MaxValue)
                        {
                            throw new CBORException("Length" + ToUnsignedEInteger(len) +
                                                    " is bigger than supported");
                        }
                        if (nextByte != 0x60)
                        {
                            // NOTE: 0x60 means the empty string
                            if (PropertyMap.ExceedsKnownLength(this.stream, len))
                            {
                                throw new CBORException("Premature end of data");
                            }
                            switch (
                                DataUtilities.ReadUtf8(
                                    this.stream,
                                    (int)len,
                                    builder,
                                    false))
                            {
                            case -1:
                                throw new CBORException("Invalid UTF-8");

                            case -2:
                                throw new CBORException("Premature end of data");
                            }
                        }
                    }
                    return(CBORObject.FromRaw(builder.ToString()));
                }

                case 4: {
                    CBORObject cbor    = CBORObject.NewArray();
                    var        vtindex = 0;
                    // Indefinite-length array
                    while (true)
                    {
                        int headByte = this.stream.ReadByte();
                        if (headByte < 0)
                        {
                            throw new CBORException("Premature end of data");
                        }
                        if (headByte == 0xff)
                        {
                            // Break code was read
                            break;
                        }
                        ++this.depth;
                        CBORObject o = this.ReadForFirstByte(
                            headByte);
                        --this.depth;
                        cbor.Add(o);
                        ++vtindex;
                    }
                    return(cbor);
                }

                case 5: {
                    CBORObject cbor = CBORObject.NewMap();
                    // Indefinite-length map
                    while (true)
                    {
                        int headByte = this.stream.ReadByte();
                        if (headByte < 0)
                        {
                            throw new CBORException("Premature end of data");
                        }
                        if (headByte == 0xff)
                        {
                            // Break code was read
                            break;
                        }
                        ++this.depth;
                        CBORObject key   = this.ReadForFirstByte(headByte);
                        CBORObject value = this.ReadInternal();
                        --this.depth;
                        int oldCount = cbor.Count;
                        cbor[key] = value;
                        int newCount = cbor.Count;
                        if (!this.options.AllowDuplicateKeys && oldCount == newCount)
                        {
                            throw new CBORException("Duplicate key already exists");
                        }
                    }
                    return(cbor);
                }

                default: throw new CBORException("Unexpected data encountered");
                }
            }
            EInteger bigintAdditional = EInteger.Zero;

            uadditional = ReadDataLength(this.stream, firstbyte, type);
            // The following doesn't check for major types 0 and 1,
            // since all of them are fixed-length types and are
            // handled in the call to GetFixedLengthObject.
            if (type >= 2 && type <= 5)
            {
                return(this.ReadStringArrayMap(type, uadditional));
            }
            if (type == 6) // Tagged item
            {
                var haveFirstByte = false;
                var newFirstByte  = -1;
                if (this.options.ResolveReferences && (uadditional >> 32) == 0)
                {
                    // NOTE: HandleItemTag treats only certain tags up to 256 specially
                    this.HandleItemTag(uadditional);
                }
                ++this.depth;
                CBORObject o = haveFirstByte ? this.ReadForFirstByte(
                    newFirstByte) : this.ReadInternal();
                --this.depth;
                if ((uadditional >> 63) != 0)
                {
                    return(CBORObject.FromObjectAndTag(o,
                                                       ToUnsignedEInteger(uadditional)));
                }
                if (uadditional < 65536)
                {
                    if (this.options.ResolveReferences)
                    {
                        int uaddl = uadditional >= 257 ? 257 : (uadditional < 0 ? 0 :
                                                                (int)uadditional);
                        switch (uaddl)
                        {
                        case 256:
                            // string tag
                            this.stringRefs.Pop();
                            break;

                        case 25:
                            // stringref tag
                            if (o.IsTagged || o.Type != CBORType.Integer)
                            {
                                throw new CBORException("stringref must be an unsigned" +
                                                        "\u0020integer");
                            }
                            return(this.stringRefs.GetString(o.AsEIntegerValue()));
                        }
                    }
                    return(CBORObject.FromObjectAndTag(
                               o,
                               (int)uadditional));
                }
                return(CBORObject.FromObjectAndTag(
                           o,
                           (EInteger)uadditional));
            }
            throw new CBORException("Unexpected data encountered");
        }
Esempio n. 2
0
        private CBORObject ReadStringArrayMap(int type, long uadditional)
        {
            bool canonical = this.options.Ctap2Canonical;

            if (type == 2 || type == 3) // Byte string or text string
            {
                if ((uadditional >> 31) != 0)
                {
                    throw new CBORException("Length of " +
                                            ToUnsignedEInteger(uadditional).ToString() + " is bigger" +
                                            "\u0020than supported");
                }
                int hint = (uadditional > Int32.MaxValue ||
                            (uadditional >> 63) != 0) ? Int32.MaxValue : (int)uadditional;
                byte[] data = ReadByteData(this.stream, uadditional, null);
                if (type == 3)
                {
                    if (!CBORUtilities.CheckUtf8(data))
                    {
                        throw new CBORException("Invalid UTF-8");
                    }
                    return(this.ObjectFromUtf8Array(data, hint));
                }
                else
                {
                    return(this.ObjectFromByteArray(data, hint));
                }
            }
            if (type == 4) // Array
            {
                if (this.options.Ctap2Canonical && this.depth >= 4)
                {
                    throw new CBORException("Depth too high in canonical CBOR");
                }
                CBORObject cbor = CBORObject.NewArray();
                if ((uadditional >> 31) != 0)
                {
                    throw new CBORException("Length of " +
                                            ToUnsignedEInteger(uadditional).ToString() + " is bigger than" +
                                            "\u0020supported");
                }
                if (PropertyMap.ExceedsKnownLength(this.stream, uadditional))
                {
                    throw new CBORException("Remaining data too small for array" +
                                            "\u0020length");
                }
                ++this.depth;
                for (long i = 0; i < uadditional; ++i)
                {
                    cbor.Add(
                        this.ReadInternal());
                }
                --this.depth;
                return(cbor);
            }
            if (type == 5) // Map, type 5
            {
                if (this.options.Ctap2Canonical && this.depth >= 4)
                {
                    throw new CBORException("Depth too high in canonical CBOR");
                }
                CBORObject cbor = CBORObject.NewMap();
                if ((uadditional >> 31) != 0)
                {
                    throw new CBORException("Length of " +
                                            ToUnsignedEInteger(uadditional).ToString() + " is bigger than" +
                                            "\u0020supported");
                }
                if (PropertyMap.ExceedsKnownLength(this.stream, uadditional))
                {
                    throw new CBORException("Remaining data too small for map" +
                                            "\u0020length");
                }
                CBORObject             lastKey  = null;
                IComparer <CBORObject> comparer = CBORCanonical.Comparer;
                for (long i = 0; i < uadditional; ++i)
                {
                    ++this.depth;
                    CBORObject key   = this.ReadInternal();
                    CBORObject value = this.ReadInternal();
                    --this.depth;
                    if (this.options.Ctap2Canonical && lastKey != null)
                    {
                        int cmp = comparer.Compare(lastKey, key);
                        if (cmp > 0)
                        {
                            throw new CBORException("Map key not in canonical order");
                        }
                        else if (cmp == 0)
                        {
                            throw new CBORException("Duplicate map key");
                        }
                    }
                    if (!this.options.AllowDuplicateKeys)
                    {
                        if (cbor.ContainsKey(key))
                        {
                            throw new CBORException("Duplicate key already exists");
                        }
                    }
                    lastKey   = key;
                    cbor[key] = value;
                }
                return(cbor);
            }
            return(null);
        }