      1 /*
      2  * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved.
      3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      4  *
      5  * This code is free software; you can redistribute it and/or modify it
      6  * under the terms of the GNU General Public License version 2 only, as
      7  * published by the Free Software Foundation.  Oracle designates this
      8  * particular file as subject to the "Classpath" exception as provided
      9  * by Oracle in the LICENSE file that accompanied this code.
     10  *
     11  * This code is distributed in the hope that it will be useful, but WITHOUT
     12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     14  * version 2 for more details (a copy is included in the LICENSE file that
     15  * accompanied this code).
     16  *
     17  * You should have received a copy of the GNU General Public License version
     18  * 2 along with this work; if not, write to the Free Software Foundation,
     19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     20  *
     21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     22  * or visit www.oracle.com if you need additional information or have any
     23  * questions.
     24  */
     25
     26 package javax.smartcardio;
     27
     28 import java.util.Arrays;
     29 import java.io.IOException;
     30
     31 /**
     32  * A response APDU as defined in ISO/IEC 7816-4. It consists of a conditional
     33  * body and a two byte trailer.
     34  * This class does not attempt to verify that the APDU encodes a semantically
     35  * valid response.
     36  *
     37  * <p>Instances of this class are immutable. Where data is passed in or out
     38  * via byte arrays, defensive cloning is performed.
     39  *
     40  * @see CommandAPDU
     41  * @see CardChannel#transmit CardChannel.transmit
     42  *
     43  * @since   1.6
     44  * @author  Andreas Sterbenz
     45  * @author  JSR 268 Expert Group
     46  */
     47 public final class ResponseAPDU implements java.io.Serializable {
     48
     49     private static final long serialVersionUID = 6962744978375594225L;
     50
     51     /** @serial */
     52     private byte[] apdu;
     53
     54     /**
     55      * Constructs a ResponseAPDU from a byte array containing the complete
     56      * APDU contents (conditional body and trailed).
     57      *
     58      * <p>Note that the byte array is cloned to protect against subsequent
     59      * modification.
     60      *
     61      * @param apdu the complete response APDU
     62      *
     63      * @throws NullPointerException if apdu is null
     64      * @throws IllegalArgumentException if apdu.length is less than 2
     65      */
     66     public ResponseAPDU(byte[] apdu) {
     67         apdu = apdu.clone();
     68         check(apdu);
     69         this.apdu = apdu;
     70     }
     71
     72     private static void check(byte[] apdu) {
     73         if (apdu.length < 2) {
     74             throw new IllegalArgumentException("apdu must be at least 2 bytes long");
     75         }
     76     }
     77
     78     /**
     79      * Returns the number of data bytes in the response body (Nr) or 0 if this
     80      * APDU has no body. This call is equivalent to
     81      * <code>getData().length</code>.
     82      *
     83      * @return the number of data bytes in the response body or 0 if this APDU
     84      * has no body.
     85      */
     86     public int getNr() {
     87         return apdu.length - 2;
     88     }
     89
     90     /**
     91      * Returns a copy of the data bytes in the response body. If this APDU as
     92      * no body, this method returns a byte array with a length of zero.
     93      *
     94      * @return a copy of the data bytes in the response body or the empty
     95      *    byte array if this APDU has no body.
     96      */
     97     public byte[] getData() {
     98         byte[] data = new byte[apdu.length - 2];
     99         System.arraycopy(apdu, 0, data, 0, data.length);
    100         return data;
    101     }
    102
    103     /**
    104      * Returns the value of the status byte SW1 as a value between 0 and 255.
    105      *
    106      * @return the value of the status byte SW1 as a value between 0 and 255.
    107      */
    108     public int getSW1() {
    109         return apdu[apdu.length - 2] & 0xff;
    110     }
    111
    112     /**
    113      * Returns the value of the status byte SW2 as a value between 0 and 255.
    114      *
    115      * @return the value of the status byte SW2 as a value between 0 and 255.
    116      */
    117     public int getSW2() {
    118         return apdu[apdu.length - 1] & 0xff;
    119     }
    120
    121     /**
    122      * Returns the value of the status bytes SW1 and SW2 as a single
    123      * status word SW.
    124      * It is defined as
    125      * {@code (getSW1() << 8) | getSW2()}
    126      *
    127      * @return the value of the status word SW.
    128      */
    129     public int getSW() {
    130         return (getSW1() << 8) | getSW2();
    131     }
    132
    133     /**
    134      * Returns a copy of the bytes in this APDU.
    135      *
    136      * @return a copy of the bytes in this APDU.
    137      */
    138     public byte[] getBytes() {
    139         return apdu.clone();
    140     }
    141
    142     /**
    143      * Returns a string representation of this response APDU.
    144      *
    145      * @return a String representation of this response APDU.
    146      */
    147     public String toString() {
    148         return "ResponseAPDU: " + apdu.length + " bytes, SW="
    149             + Integer.toHexString(getSW());
    150     }
    151
    152     /**
    153      * Compares the specified object with this response APDU for equality.
    154      * Returns true if the given object is also a ResponseAPDU and its bytes are
    155      * identical to the bytes in this ResponseAPDU.
    156      *
    157      * @param obj the object to be compared for equality with this response APDU
    158      * @return true if the specified object is equal to this response APDU
    159      */
    160     public boolean equals(Object obj) {
    161         if (this == obj) {
    162             return true;
    163         }
    164         if (obj instanceof ResponseAPDU == false) {
    165             return false;
    166         }
    167         ResponseAPDU other = (ResponseAPDU)obj;
    168         return Arrays.equals(this.apdu, other.apdu);
    169     }
    170
    171     /**
    172      * Returns the hash code value for this response APDU.
    173      *
    174      * @return the hash code value for this response APDU.
    175      */
    176     public int hashCode() {
    177         return Arrays.hashCode(apdu);
    178     }
    179
    180     /**
    181      * Restores the state of this object from the stream.
    182      *
    183      * @param  in the {@code ObjectInputStream} from which data is read
    184      * @throws IOException if an I/O error occurs
    185      * @throws ClassNotFoundException if a serialized class cannot be loaded
    186      */
    187     private void readObject(java.io.ObjectInputStream in)
    188             throws IOException, ClassNotFoundException {
    189         apdu = (byte[])in.readUnshared();
    190         check(apdu);
    191     }
    192
    193 }