• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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 android.carrierapi.cts;
18 
19 import static android.carrierapi.cts.IccUtils.hexStringToBytes;
20 
21 import java.util.ArrayList;
22 import java.util.List;
23 import java.util.Objects;
24 import javax.annotation.Nonnull;
25 
26 /**
27  * Class for representing a File Control Parameters (FCP) Template object. TS 101 220
28  *
29  * A correctly formatted FCP Template will be in the format:
30  * | 1 byte: BER tag (0x62) | 1 byte: length of TLVs |...TLV objects...| 2 bytes: status |
31  */
32 public class FcpTemplate {
33 
34     // FCP Template label
35     public static final int BER_TAG_FCP_TEMPLATE = 0x62;
36 
37     // FCP Template BER-TLV Tag tags. TS 101 220 Section 7.2
38     public static final int FILE_SIZE_DATA = 0x80;
39     public static final int FILE_SIZE_TOTAL = 0x81;
40     public static final int FILE_DESCRIPTOR = 0x82;
41     public static final int FILE_IDENTIFIER = 0x83;
42     public static final int DF_NAME = 0x84;
43     public static final int PROPRIETARY = 0x85;
44     public static final int SFI_SUPPORT = 0x88;
45     public static final int LIFE_CYCLE_STATUS = 0x8A;
46     public static final int SECURITY_ATTR_REFERENCE_FORMAT = 0x8B;
47     public static final int SECURITY_ATTR_COMPACT_FORMAT = 0x8C;
48     public static final int SECURITY_ATTR_TEMPLATE_EXPANDED_FORMAT = 0xAB;
49     public static final int PROPRIETARY_TEMPLATE = 0xA5;
50     public static final int PIN_STATUS_DATA_OBJECT = 0xC6;
51 
52     private final List<Tlv> tlvs;
53     private final String status;
54 
FcpTemplate(@onnull List<Tlv> tlvs, @Nonnull String status)55     private FcpTemplate(@Nonnull List<Tlv> tlvs, @Nonnull String status) {
56         this.tlvs = tlvs;
57         this.status = status;
58     }
59 
getTlvs()60     public List<Tlv> getTlvs() {
61         return tlvs;
62     }
63 
getStatus()64     public String getStatus() {
65         return status;
66     }
67 
68     /**
69      * Parses and returns a FcpTemplate for the given {@code fcpResponse}
70      *
71      * @param fcpResponse The Hex String response for a given Status APDU command. Expected to be in
72      * the format: | 1 byte: BER tag | 1 byte: length of TLVs |...TLV objects...| 2 bytes: status |
73      *
74      * @return a FcpTemplate for the given hex String
75      *
76      * @throws FcpTemplateParseException for non-FCP inputs or inputs of the wrong length (encoded
77      *                                   length does not match actual length)
78      */
parseFcpTemplate(@onnull String fcpResponse)79     public static FcpTemplate parseFcpTemplate(@Nonnull String fcpResponse) {
80         final List<Tlv> tlvObjects = new ArrayList<>();
81 
82         // Expected FcpResponse format:
83         // | 1 byte: BER tag | 1 byte: length of TLVs | ...TLV objects... | 2 bytes: status |
84         byte[] data = hexStringToBytes(fcpResponse);
85         int responseLength = data.length;
86         // don't count BER tag, length byte, or status bytes
87         int payloadLength = responseLength - 4;
88         // data[0]: Response tag
89         // data[1]: TLV data object length in bytes. Assumes that length is < 128 bytes
90         if (data[0] != BER_TAG_FCP_TEMPLATE || data[1] != payloadLength) {
91             throw new FcpTemplateParseException("Improperly formatted fcpResponse: " + fcpResponse);
92         }
93 
94         int index = 2;
95         while (index < responseLength - 2) { // don't need to process the 2 byte status-word footer
96             // TLV data object format per TS 101 220:
97             // | 1 byte: tag | 1 byte: length | 'length' bytes: value |
98             int tag = data[index++] & 0xFF;
99             int length = data[index++] & 0xFF; // assumes that length is < 128 bytes.
100             String value = fcpResponse.substring(index * 2, (index + length) * 2);
101             tlvObjects .add(new Tlv(tag, length, value));
102             index += length;
103         }
104 
105         String status = fcpResponse.substring(fcpResponse.length() - 4);
106         return new FcpTemplate(tlvObjects , status);
107     }
108 
109     /**
110      * Represents a Tag-Length-Value object. TS 101 220 Section 2
111      */
112     public static class Tlv {
113 
114         private final int tag;
115         private final int length;
116         private final String value;
117 
Tlv(int tag, int length, @Nonnull String value)118         public Tlv(int tag, int length, @Nonnull String value) {
119             this.tag = tag;
120             this.length = length;
121             this.value = value;
122         }
123 
getTag()124         public int getTag() {
125             return tag;
126         }
127 
getLength()128         public int getLength() {
129             return length;
130         }
131 
getValue()132         public String getValue() {
133             return value;
134         }
135 
136         @Override
equals(Object o)137         public boolean equals(Object o) {
138             if (this == o) {
139                 return true;
140             }
141             if (o == null || getClass() != o.getClass()) {
142                 return false;
143             }
144             Tlv tlv = (Tlv) o;
145             return tag == tlv.tag &&
146                     length == tlv.length &&
147                     value.equals(tlv.value);
148         }
149 
150         @Override
hashCode()151         public int hashCode() {
152             return Objects.hash(tag, length, value);
153         }
154 
155         @Override
toString()156         public String toString() {
157             return tag + "(" + length + "):" + value;
158         }
159     }
160 
161     private static final class FcpTemplateParseException extends RuntimeException {
162 
FcpTemplateParseException(String message)163         public FcpTemplateParseException(String message) {
164             super(message);
165         }
166     }
167 }
168