1 /* 2 * Copyright (C) 2021 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 package com.android.server.uwb.secure.iso7816; 17 18 import androidx.annotation.Nullable; 19 20 import com.google.common.base.Objects; 21 import com.google.common.base.Preconditions; 22 import com.google.common.collect.ImmutableSet; 23 import com.google.common.primitives.Shorts; 24 25 import java.util.Collections; 26 import java.util.LinkedHashMap; 27 import java.util.Map; 28 29 /** Representation of some common ISO7816-4 and GlobalPlatform status words. */ 30 public final class StatusWord { 31 32 public static final StatusWord SW_NO_ERROR = 33 new StatusWord(0x9000, "no error"); 34 35 public static final StatusWord SW_RESPONSE_BYTES_STILL_AVAILABLE = 36 new StatusWord(0x6100, "Response bytes still available"); 37 38 public static final StatusWord SW_WARNING_STATE_UNCHANGED = 39 new StatusWord(0x6200, "Warning: State unchanged"); 40 41 public static final StatusWord SW_CARD_MANAGER_LOCKED = 42 new StatusWord(0x6283, "Warning: Card Manager is locked"); 43 44 public static final StatusWord SW_WARNING_NO_INFO_GIVEN = 45 new StatusWord(0x6300, "Warning: State changed (no information given)"); 46 47 public static final StatusWord SW_WARNING_MORE_DATA = 48 new StatusWord(0x6310, "more data"); 49 50 public static final StatusWord SW_VERIFY_FAILED = 51 new StatusWord(0x63C0, "PIN authentication failed."); 52 53 public static final StatusWord SW_NO_SPECIFIC_DIAGNOSTIC = 54 new StatusWord(0x6400, "No specific diagnostic"); 55 56 public static final StatusWord SW_REQUESTED_ELEMENTS_NOT_AVAILABLE = 57 new StatusWord(0x6402, "Requested elements not available"); 58 59 public static final StatusWord SW_ICA_ALREADY_EXISTS = 60 new StatusWord(0x6409, "ICA Already Exists"); 61 62 public static final StatusWord SW_WRONG_LENGTH = 63 new StatusWord(0x6700, "Wrong length"); 64 65 public static final StatusWord SW_SECURITY_STATUS_NOT_SATISFIED = 66 new StatusWord(0x6982, "Security status not satisfied"); 67 68 public static final StatusWord SW_FILE_INVALID = 69 new StatusWord(0x6983, "File invalid"); 70 71 public static final StatusWord SW_REFERENCE_DATA_NOT_USABLE = 72 new StatusWord(0x6984, "Reference data not usable"); 73 74 public static final StatusWord SW_CONDITIONS_NOT_SATISFIED = 75 new StatusWord(0x6985, "Conditions of use not satisfied"); 76 77 public static final StatusWord SW_COMMAND_NOT_ALLOWED = 78 new StatusWord(0x6986, "Command not allowed"); 79 80 public static final StatusWord SW_APPLET_SELECT_FAILED = 81 new StatusWord(0x6999, "Applet selection failed"); 82 83 public static final StatusWord SW_WRONG_DATA = 84 new StatusWord(0x6A80, "Wrong data"); 85 86 public static final StatusWord SW_FUNCTION_NOT_SUPPORTED = 87 new StatusWord(0x6A81, "Function not supported"); 88 89 public static final StatusWord SW_FILE_NOT_FOUND = 90 new StatusWord(0x6A82, "File not found"); 91 92 public static final StatusWord SW_RECORD_NOT_FOUND = 93 new StatusWord(0x6A83, "Record not found"); 94 95 public static final StatusWord SW_NOT_ENOUGH_MEMORY = 96 new StatusWord(0x6A84, "Not enough memory"); 97 98 public static final StatusWord SW_NC_INCONSISTENT_WITH_TLV = 99 new StatusWord(0x6A85, "Nc inconsistent with TLV structure"); 100 101 public static final StatusWord SW_INCORRECT_P1P2 = 102 new StatusWord(0x6A86, "Incorrect P1 or P2"); 103 104 public static final StatusWord SW_DATA_NOT_FOUND = 105 new StatusWord(0x6A88, "Referenced data not found"); 106 107 public static final StatusWord SW_FILE_ALREADY_EXISTS = 108 new StatusWord(0x6A89, "File already exists"); 109 110 public static final StatusWord SW_WRONG_P1P2 = 111 new StatusWord(0x6B00, "Wrong P1 or P2"); 112 113 public static final StatusWord SW_WRONG_LE = 114 new StatusWord(0x6C00, "Wrong Le"); 115 116 public static final StatusWord SW_INS_NOT_SUPPORTED = 117 new StatusWord(0x6D00, "Instruction not supported or invalid"); 118 119 public static final StatusWord SW_CLA_NOT_SUPPORTED = 120 new StatusWord(0x6E00, "Class not supported"); 121 122 public static final StatusWord SW_UNKNOWN_ERROR = 123 new StatusWord(0x6F00, "Unknown error (no precise diagnosis)"); 124 125 private static final String UNKNOWN_STATUS_WORD_MESSAGE = "Unknown status word"; 126 127 public static final ImmutableSet<StatusWord> ALL_KNOWN_STATUS_WORDS = 128 ImmutableSet.of( 129 SW_NO_ERROR, 130 SW_RESPONSE_BYTES_STILL_AVAILABLE, 131 SW_WARNING_STATE_UNCHANGED, 132 SW_CARD_MANAGER_LOCKED, 133 SW_WARNING_NO_INFO_GIVEN, 134 SW_WARNING_MORE_DATA, 135 SW_VERIFY_FAILED, 136 SW_NO_SPECIFIC_DIAGNOSTIC, 137 SW_REQUESTED_ELEMENTS_NOT_AVAILABLE, 138 SW_ICA_ALREADY_EXISTS, 139 SW_WRONG_LENGTH, 140 SW_SECURITY_STATUS_NOT_SATISFIED, 141 SW_FILE_INVALID, 142 SW_REFERENCE_DATA_NOT_USABLE, 143 SW_CONDITIONS_NOT_SATISFIED, 144 SW_COMMAND_NOT_ALLOWED, 145 SW_APPLET_SELECT_FAILED, 146 SW_WRONG_DATA, 147 SW_FUNCTION_NOT_SUPPORTED, 148 SW_FILE_NOT_FOUND, 149 SW_RECORD_NOT_FOUND, 150 SW_NOT_ENOUGH_MEMORY, 151 SW_NC_INCONSISTENT_WITH_TLV, 152 SW_INCORRECT_P1P2, 153 SW_DATA_NOT_FOUND, 154 SW_FILE_ALREADY_EXISTS, 155 SW_WRONG_P1P2, 156 SW_WRONG_LE, 157 SW_INS_NOT_SUPPORTED, 158 SW_CLA_NOT_SUPPORTED, 159 SW_UNKNOWN_ERROR); 160 161 /** A meessage that is used to construct an exception to represent this status word. */ 162 private final String mMessage; 163 164 /** The actual status word (2 bytes). */ 165 private final int mStatusWord; 166 167 /** Map status words to values for fast lookup. */ 168 private static final Map<Integer, StatusWord> STATUS_WORD_MAP; 169 170 static { 171 // Map all the values to their code. 172 Map<Integer, StatusWord> statusWordMap = new LinkedHashMap<>(ALL_KNOWN_STATUS_WORDS.size()); 173 for (StatusWord value : ALL_KNOWN_STATUS_WORDS) { Integer.valueOf(value.mStatusWord)174 statusWordMap.put(Integer.valueOf(value.mStatusWord), value); 175 } 176 STATUS_WORD_MAP = Collections.unmodifiableMap(statusWordMap); 177 } 178 StatusWord(int sw, String message)179 private StatusWord(int sw, String message) { 180 mStatusWord = sw; 181 this.mMessage = message; 182 } 183 184 /** Lookup a {@link StatusWord} from the status word value. */ fromInt(int sw)185 public static StatusWord fromInt(int sw) { 186 Preconditions.checkArgument((sw >> Short.SIZE) == 0); 187 StatusWord statusWord = STATUS_WORD_MAP.get(Integer.valueOf(sw)); 188 if (statusWord != null) { 189 return statusWord; 190 } 191 return new StatusWord(sw, UNKNOWN_STATUS_WORD_MESSAGE); 192 } 193 194 /** 195 * Gets the byte array form of the status word. 196 */ toBytes()197 public byte[] toBytes() { 198 Preconditions.checkState((mStatusWord >> Short.SIZE) == 0); 199 return Shorts.toByteArray((short) mStatusWord); 200 } 201 202 /** 203 * Gets the int value of the status word. 204 */ toInt()205 public int toInt() { 206 return mStatusWord; 207 } 208 209 /** 210 * Gets the description message of the status word. 211 */ getMessage()212 public String getMessage() { 213 return mMessage; 214 } 215 216 /** 217 * Checks if this status word is known. 218 */ isKnown()219 public boolean isKnown() { 220 return ALL_KNOWN_STATUS_WORDS.contains(this); 221 } 222 223 /** 224 * Checks if the given status words are known. 225 */ areAllKnown(Iterable<StatusWord> statusWords)226 public static boolean areAllKnown(Iterable<StatusWord> statusWords) { 227 for (StatusWord word : statusWords) { 228 if (!word.isKnown()) { 229 return false; 230 } 231 } 232 return true; 233 } 234 235 @Override toString()236 public String toString() { 237 return String.format("'%04X': %s", mStatusWord, mMessage); 238 } 239 240 @Override equals(@ullable Object obj)241 public boolean equals(@Nullable Object obj) { 242 if (obj == null || obj.getClass() != this.getClass()) { 243 return false; 244 } 245 246 StatusWord other = (StatusWord) obj; 247 return other.mStatusWord == this.mStatusWord; 248 } 249 250 @Override hashCode()251 public int hashCode() { 252 return Objects.hashCode(mStatusWord); 253 } 254 } 255