1 /* 2 * Copyright (C) 2018 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.euicc; 18 19 import android.telephony.Rlog; 20 21 import com.android.internal.telephony.uicc.asn1.Asn1Decoder; 22 import com.android.internal.telephony.uicc.asn1.Asn1Node; 23 import com.android.internal.telephony.uicc.asn1.InvalidAsn1DataException; 24 import com.android.internal.telephony.uicc.asn1.TagNotFoundException; 25 26 import java.util.Arrays; 27 28 /** 29 * This represents the version of GSMA SGP.22 spec in the form of 3 numbers: major, minor, and 30 * revision. 31 */ 32 public final class EuiccSpecVersion implements Comparable<EuiccSpecVersion> { 33 private static final String LOG_TAG = "EuiccSpecVer"; 34 35 // ASN.1 Tags 36 private static final int TAG_ISD_R_APP_TEMPLATE = 0xE0; 37 private static final int TAG_VERSION = 0x82; 38 39 private final int[] mVersionValues = new int[3]; 40 41 /** 42 * Parses the response of opening a logical channel to get spec version of the eUICC card. 43 * 44 * @return Parsed spec version. If any error is encountered, null will be returned. 45 */ fromOpenChannelResponse(byte[] response)46 public static EuiccSpecVersion fromOpenChannelResponse(byte[] response) { 47 Asn1Node node; 48 try { 49 Asn1Decoder decoder = new Asn1Decoder(response); 50 if (!decoder.hasNextNode()) { 51 return null; 52 } 53 node = decoder.nextNode(); 54 } catch (InvalidAsn1DataException e) { 55 Rlog.e(LOG_TAG, "Cannot parse the select response of ISD-R.", e); 56 return null; 57 } 58 try { 59 byte[] versionType; 60 if (node.getTag() == TAG_ISD_R_APP_TEMPLATE) { 61 versionType = node.getChild(TAG_VERSION).asBytes(); 62 } else { 63 versionType = 64 node.getChild(TAG_ISD_R_APP_TEMPLATE, TAG_VERSION).asBytes(); 65 } 66 if (versionType.length == 3) { 67 return new EuiccSpecVersion(versionType); 68 } else { 69 Rlog.e(LOG_TAG, "Cannot parse select response of ISD-R: " + node.toHex()); 70 } 71 } catch (InvalidAsn1DataException | TagNotFoundException e) { 72 Rlog.e(LOG_TAG, "Cannot parse select response of ISD-R: " + node.toHex()); 73 } 74 return null; 75 } 76 EuiccSpecVersion(int major, int minor, int revision)77 public EuiccSpecVersion(int major, int minor, int revision) { 78 mVersionValues[0] = major; 79 mVersionValues[1] = minor; 80 mVersionValues[2] = revision; 81 } 82 83 /** 84 * @param version The version bytes from ASN1 data. The length must be 3. 85 */ EuiccSpecVersion(byte[] version)86 public EuiccSpecVersion(byte[] version) { 87 mVersionValues[0] = version[0] & 0xFF; 88 mVersionValues[1] = version[1] & 0xFF; 89 mVersionValues[2] = version[2] & 0xFF; 90 } 91 getMajor()92 public int getMajor() { 93 return mVersionValues[0]; 94 } 95 getMinor()96 public int getMinor() { 97 return mVersionValues[1]; 98 } 99 getRevision()100 public int getRevision() { 101 return mVersionValues[2]; 102 } 103 104 @Override compareTo(EuiccSpecVersion that)105 public int compareTo(EuiccSpecVersion that) { 106 if (getMajor() > that.getMajor()) { 107 return 1; 108 } else if (getMajor() < that.getMajor()) { 109 return -1; 110 } 111 if (getMinor() > that.getMinor()) { 112 return 1; 113 } else if (getMinor() < that.getMinor()) { 114 return -1; 115 } 116 if (getRevision() > that.getRevision()) { 117 return 1; 118 } else if (getRevision() < that.getRevision()) { 119 return -1; 120 } 121 return 0; 122 } 123 124 @Override equals(Object obj)125 public boolean equals(Object obj) { 126 if (this == obj) { 127 return true; 128 } 129 if (obj == null || getClass() != obj.getClass()) { 130 return false; 131 } 132 return Arrays.equals(mVersionValues, ((EuiccSpecVersion) obj).mVersionValues); 133 } 134 135 @Override hashCode()136 public int hashCode() { 137 return Arrays.hashCode(mVersionValues); 138 } 139 140 @Override toString()141 public String toString() { 142 return mVersionValues[0] + "." + mVersionValues[1] + "." + mVersionValues[2]; 143 } 144 } 145