• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.internal.telephony.uicc.asn1;
18 
19 import com.android.internal.telephony.uicc.IccUtils;
20 
21 /**
22  * This represents a decoder helping decode an array of bytes or a hex string into
23  * {@link Asn1Node}s. This class tracks the next position for decoding. This class is not
24  * thread-safe.
25  */
26 public final class Asn1Decoder {
27     // Source byte array.
28     private final byte[] mSrc;
29     // Next position of the byte in the source array for decoding.
30     private int mPosition;
31     // Exclusive end of the range in the array for decoding.
32     private final int mEnd;
33 
34     /** Creates a decoder on a hex string. */
Asn1Decoder(String hex)35     public Asn1Decoder(String hex) {
36         this(IccUtils.hexStringToBytes(hex));
37     }
38 
39     /** Creates a decoder on a byte array. */
Asn1Decoder(byte[] src)40     public Asn1Decoder(byte[] src) {
41         this(src, 0, src.length);
42     }
43 
44     /**
45      * Creates a decoder on a byte array slice.
46      *
47      * @throws IndexOutOfBoundsException If the range defined by {@code offset} and {@code length}
48      *         exceeds the bounds of {@code bytes}.
49      */
Asn1Decoder(byte[] bytes, int offset, int length)50     public Asn1Decoder(byte[] bytes, int offset, int length) {
51         if (offset < 0 || length < 0 || offset + length > bytes.length) {
52             throw new IndexOutOfBoundsException(
53                     "Out of the bounds: bytes=["
54                             + bytes.length
55                             + "], offset="
56                             + offset
57                             + ", length="
58                             + length);
59         }
60         mSrc = bytes;
61         mPosition = offset;
62         mEnd = offset + length;
63     }
64 
65     /** @return The next start position for decoding. */
getPosition()66     public int getPosition() {
67         return mPosition;
68     }
69 
70     /** Returns whether the node has a next node. */
hasNextNode()71     public boolean hasNextNode() {
72         return mPosition < mEnd;
73     }
74 
75     /**
76      * Parses the next node. If the node is a constructed node, its children will be parsed only
77      * when they are accessed, e.g., though {@link Asn1Node#getChildren()}.
78      *
79      * @return The next decoded {@link Asn1Node}. If success, the next decoding position will also
80      *         be updated. If any error happens, e.g., moving over the end position, {@code null}
81      *         will be returned and the next decoding position won't be modified.
82      * @throws InvalidAsn1DataException If the bytes cannot be parsed.
83      */
nextNode()84     public Asn1Node nextNode() throws InvalidAsn1DataException {
85         if (mPosition >= mEnd) {
86             throw new IllegalStateException("No bytes to parse.");
87         }
88 
89         int offset = mPosition;
90 
91         // Extracts the tag.
92         int tagStart = offset;
93         byte b = mSrc[offset++];
94         if ((b & 0x1F) == 0x1F) {
95             // High-tag-number form
96             while (offset < mEnd && (mSrc[offset++] & 0x80) != 0) {
97                 // Do nothing.
98             }
99         }
100         if (offset >= mEnd) {
101             // No length bytes or the tag is too long.
102             throw new InvalidAsn1DataException(0, "Invalid length at position: " + offset);
103         }
104         int tag;
105         try {
106             tag = IccUtils.bytesToInt(mSrc, tagStart, offset - tagStart);
107         } catch (IllegalArgumentException e) {
108             // Cannot parse the tag as an integer.
109             throw new InvalidAsn1DataException(0, "Cannot parse tag at position: " + tagStart, e);
110         }
111 
112         // Extracts the length.
113         int dataLen;
114         b = mSrc[offset++];
115         if ((b & 0x80) == 0) {
116             // Short-form length
117             dataLen = b;
118         } else {
119             // Long-form length
120             int lenLen = b & 0x7F;
121             if (offset + lenLen > mEnd) {
122                 // No enough bytes for the long-form length
123                 throw new InvalidAsn1DataException(
124                         tag, "Cannot parse length at position: " + offset);
125             }
126             try {
127                 dataLen = IccUtils.bytesToInt(mSrc, offset, lenLen);
128             } catch (IllegalArgumentException e) {
129                 // Cannot parse the data length as an integer.
130                 throw new InvalidAsn1DataException(
131                         tag, "Cannot parse length at position: " + offset, e);
132             }
133             offset += lenLen;
134         }
135         if (offset + dataLen > mEnd) {
136             // No enough data left.
137             throw new InvalidAsn1DataException(
138                     tag,
139                     "Incomplete data at position: "
140                             + offset
141                             + ", expected bytes: "
142                             + dataLen
143                             + ", actual bytes: "
144                             + (mEnd - offset));
145         }
146 
147         Asn1Node root = new Asn1Node(tag, mSrc, offset, dataLen);
148         mPosition = offset + dataLen;
149         return root;
150     }
151 }
152