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