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