      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
     30 import java.nio.ByteBuffer;
     31 import java.io.IOException;
     32
     33 /**
     34  * A command APDU following the structure defined in ISO/IEC 7816-4.
     35  * It consists of a four byte header and a conditional body of variable length.
     36  * This class does not attempt to verify that the APDU encodes a semantically
     37  * valid command.
     38  *
     39  * <p>Note that when the expected length of the response APDU is specified
     40  * in the {@linkplain #CommandAPDU(int,int,int,int,int) constructors},
     41  * the actual length (Ne) must be specified, not its
     42  * encoded form (Le). Similarly, {@linkplain #getNe} returns the actual
     43  * value Ne. In other words, a value of 0 means "no data in the response APDU"
     44  * rather than "maximum length."
     45  *
     46  * <p>This class supports both the short and extended forms of length
     47  * encoding for Ne and Nc. However, note that not all terminals and Smart Cards
     48  * are capable of accepting APDUs that use the extended form.
     49  *
     50  * <p>For the header bytes CLA, INS, P1, and P2 the Java type <code>int</code>
     51  * is used to represent the 8 bit unsigned values. In the constructors, only
     52  * the 8 lowest bits of the <code>int</code> value specified by the application
     53  * are significant. The accessor methods always return the byte as an unsigned
     54  * value between 0 and 255.
     55  *
     56  * <p>Instances of this class are immutable. Where data is passed in or out
     57  * via byte arrays, defensive cloning is performed.
     58  *
     59  * @see ResponseAPDU
     60  * @see CardChannel#transmit CardChannel.transmit
     61  *
     62  * @since   1.6
     63  * @author  Andreas Sterbenz
     64  * @author  JSR 268 Expert Group
     65  */
     66 public final class CommandAPDU implements java.io.Serializable {
     67
     68     private static final long serialVersionUID = 398698301286670877L;
     69
     70     private static final int MAX_APDU_SIZE = 65544;
     71
     72     /** @serial */
     73     private byte[] apdu;
     74
     75     // value of nc
     76     private transient int nc;
     77
     78     // value of ne
     79     private transient int ne;
     80
     81     // index of start of data within the apdu array
     82     private transient int dataOffset;
     83
     84     /**
     85      * Constructs a CommandAPDU from a byte array containing the complete
     86      * APDU contents (header and body).
     87      *
     88      * <p>Note that the apdu bytes are copied to protect against
     89      * subsequent modification.
     90      *
     91      * @param apdu the complete command APDU
     92      *
     93      * @throws NullPointerException if apdu is null
     94      * @throws IllegalArgumentException if apdu does not contain a valid
     95      *   command APDU
     96      */
     97     public CommandAPDU(byte[] apdu) {
     98         this.apdu = apdu.clone();
     99         parse();
    100     }
    101
    102     /**
    103      * Constructs a CommandAPDU from a byte array containing the complete
    104      * APDU contents (header and body). The APDU starts at the index
    105      * <code>apduOffset</code> in the byte array and is <code>apduLength</code>
    106      * bytes long.
    107      *
    108      * <p>Note that the apdu bytes are copied to protect against
    109      * subsequent modification.
    110      *
    111      * @param apdu the complete command APDU
    112      * @param apduOffset the offset in the byte array at which the apdu
    113      *   data begins
    114      * @param apduLength the length of the APDU
    115      *
    116      * @throws NullPointerException if apdu is null
    117      * @throws IllegalArgumentException if apduOffset or apduLength are
    118      *   negative or if apduOffset + apduLength are greater than apdu.length,
    119      *   or if the specified bytes are not a valid APDU
    120      */
    121     public CommandAPDU(byte[] apdu, int apduOffset, int apduLength) {
    122         checkArrayBounds(apdu, apduOffset, apduLength);
    123         this.apdu = new byte[apduLength];
    124         System.arraycopy(apdu, apduOffset, this.apdu, 0, apduLength);
    125         parse();
    126     }
    127
    128     private void checkArrayBounds(byte[] b, int ofs, int len) {
    129         if ((ofs < 0) || (len < 0)) {
    130             throw new IllegalArgumentException
    131                 ("Offset and length must not be negative");
    132         }
    133         if (b == null) {
    134             if ((ofs != 0) && (len != 0)) {
    135                 throw new IllegalArgumentException
    136                     ("offset and length must be 0 if array is null");
    137             }
    138         } else {
    139             if (ofs > b.length - len) {
    140                 throw new IllegalArgumentException
    141                     ("Offset plus length exceed array size");
    142             }
    143         }
    144     }
    145
    146     /**
    147      * Creates a CommandAPDU from the ByteBuffer containing the complete APDU
    148      * contents (header and body).
    149      * The buffer's <code>position</code> must be set to the start of the APDU,
    150      * its <code>limit</code> to the end of the APDU. Upon return, the buffer's
    151      * <code>position</code> is equal to its limit; its limit remains unchanged.
    152      *
    153      * <p>Note that the data in the ByteBuffer is copied to protect against
    154      * subsequent modification.
    155      *
    156      * @param apdu the ByteBuffer containing the complete APDU
    157      *
    158      * @throws NullPointerException if apdu is null
    159      * @throws IllegalArgumentException if apdu does not contain a valid
    160      *   command APDU
    161      */
    162     public CommandAPDU(ByteBuffer apdu) {
    163         this.apdu = new byte[apdu.remaining()];
    164         apdu.get(this.apdu);
    165         parse();
    166     }
    167
    168     /**
    169      * Constructs a CommandAPDU from the four header bytes. This is case 1
    170      * in ISO 7816, no command body.
    171      *
    172      * @param cla the class byte CLA
    173      * @param ins the instruction byte INS
    174      * @param p1 the parameter byte P1
    175      * @param p2 the parameter byte P2
    176      */
    177     public CommandAPDU(int cla, int ins, int p1, int p2) {
    178         this(cla, ins, p1, p2, null, 0, 0, 0);
    179     }
    180
    181     /**
    182      * Constructs a CommandAPDU from the four header bytes and the expected
    183      * response data length. This is case 2 in ISO 7816, empty command data
    184      * field with Ne specified. If Ne is 0, the APDU is encoded as ISO 7816
    185      * case 1.
    186      *
    187      * @param cla the class byte CLA
    188      * @param ins the instruction byte INS
    189      * @param p1 the parameter byte P1
    190      * @param p2 the parameter byte P2
    191      * @param ne the maximum number of expected data bytes in a response APDU
    192      *
    193      * @throws IllegalArgumentException if ne is negative or greater than
    194      *   65536
    195      */
    196     public CommandAPDU(int cla, int ins, int p1, int p2, int ne) {
    197         this(cla, ins, p1, p2, null, 0, 0, ne);
    198     }
    199
    200     /**
    201      * Constructs a CommandAPDU from the four header bytes and command data.
    202      * This is case 3 in ISO 7816, command data present and Ne absent. The
    203      * value Nc is taken as data.length. If <code>data</code> is null or
    204      * its length is 0, the APDU is encoded as ISO 7816 case 1.
    205      *
    206      * <p>Note that the data bytes are copied to protect against
    207      * subsequent modification.
    208      *
    209      * @param cla the class byte CLA
    210      * @param ins the instruction byte INS
    211      * @param p1 the parameter byte P1
    212      * @param p2 the parameter byte P2
    213      * @param data the byte array containing the data bytes of the command body
    214      *
    215      * @throws IllegalArgumentException if data.length is greater than 65535
    216      */
    217     public CommandAPDU(int cla, int ins, int p1, int p2, byte[] data) {
    218         this(cla, ins, p1, p2, data, 0, arrayLength(data), 0);
    219     }
    220
    221     /**
    222      * Constructs a CommandAPDU from the four header bytes and command data.
    223      * This is case 3 in ISO 7816, command data present and Ne absent. The
    224      * value Nc is taken as dataLength. If <code>dataLength</code>
    225      * is 0, the APDU is encoded as ISO 7816 case 1.
    226      *
    227      * <p>Note that the data bytes are copied to protect against
    228      * subsequent modification.
    229      *
    230      * @param cla the class byte CLA
    231      * @param ins the instruction byte INS
    232      * @param p1 the parameter byte P1
    233      * @param p2 the parameter byte P2
    234      * @param data the byte array containing the data bytes of the command body
    235      * @param dataOffset the offset in the byte array at which the data
    236      *   bytes of the command body begin
    237      * @param dataLength the number of the data bytes in the command body
    238      *
    239      * @throws NullPointerException if data is null and dataLength is not 0
    240      * @throws IllegalArgumentException if dataOffset or dataLength are
    241      *   negative or if dataOffset + dataLength are greater than data.length
    242      *   or if dataLength is greater than 65535
    243      */
    244     public CommandAPDU(int cla, int ins, int p1, int p2, byte[] data,
    245             int dataOffset, int dataLength) {
    246         this(cla, ins, p1, p2, data, dataOffset, dataLength, 0);
    247     }
    248
    249     /**
    250      * Constructs a CommandAPDU from the four header bytes, command data,
    251      * and expected response data length. This is case 4 in ISO 7816,
    252      * command data and Ne present. The value Nc is taken as data.length
    253      * if <code>data</code> is non-null and as 0 otherwise. If Ne or Nc
    254      * are zero, the APDU is encoded as case 1, 2, or 3 per ISO 7816.
    255      *
    256      * <p>Note that the data bytes are copied to protect against
    257      * subsequent modification.
    258      *
    259      * @param cla the class byte CLA
    260      * @param ins the instruction byte INS
    261      * @param p1 the parameter byte P1
    262      * @param p2 the parameter byte P2
    263      * @param data the byte array containing the data bytes of the command body
    264      * @param ne the maximum number of expected data bytes in a response APDU
    265      *
    266      * @throws IllegalArgumentException if data.length is greater than 65535
    267      *   or if ne is negative or greater than 65536
    268      */
    269     public CommandAPDU(int cla, int ins, int p1, int p2, byte[] data, int ne) {
    270         this(cla, ins, p1, p2, data, 0, arrayLength(data), ne);
    271     }
    272
    273     private static int arrayLength(byte[] b) {
    274         return (b != null) ? b.length : 0;
    275     }
    276
    277     /**
    278      * Command APDU encoding options:
    279      *
    280      * case 1:  |CLA|INS|P1 |P2 |                                 len = 4
    281      * case 2s: |CLA|INS|P1 |P2 |LE |                             len = 5
    282      * case 3s: |CLA|INS|P1 |P2 |LC |...BODY...|                  len = 6..260
    283      * case 4s: |CLA|INS|P1 |P2 |LC |...BODY...|LE |              len = 7..261
    284      * case 2e: |CLA|INS|P1 |P2 |00 |LE1|LE2|                     len = 7
    285      * case 3e: |CLA|INS|P1 |P2 |00 |LC1|LC2|...BODY...|          len = 8..65542
    286      * case 4e: |CLA|INS|P1 |P2 |00 |LC1|LC2|...BODY...|LE1|LE2|  len =10..65544
    287      *
    288      * LE, LE1, LE2 may be 0x00.
    289      * LC must not be 0x00 and LC1|LC2 must not be 0x00|0x00
    290      */
    291     private void parse() {
    292         if (apdu.length < 4) {
    293             throw new IllegalArgumentException("apdu must be at least 4 bytes long");
    294         }
    295         if (apdu.length == 4) {
    296             // case 1
    297             return;
    298         }
    299         int l1 = apdu[4] & 0xff;
    300         if (apdu.length == 5) {
    301             // case 2s
    302             this.ne = (l1 == 0) ? 256 : l1;
    303             return;
    304         }
    305         if (l1 != 0) {
    306             if (apdu.length == 4 + 1 + l1) {
    307                 // case 3s
    308                 this.nc = l1;
    309                 this.dataOffset = 5;
    310                 return;
    311             } else if (apdu.length == 4 + 2 + l1) {
    312                 // case 4s
    313                 this.nc = l1;
    314                 this.dataOffset = 5;
    315                 int l2 = apdu[apdu.length - 1] & 0xff;
    316                 this.ne = (l2 == 0) ? 256 : l2;
    317                 return;
    318             } else {
    319                 throw new IllegalArgumentException
    320                     ("Invalid APDU: length=" + apdu.length + ", b1=" + l1);
    321             }
    322         }
    323         if (apdu.length < 7) {
    324             throw new IllegalArgumentException
    325                 ("Invalid APDU: length=" + apdu.length + ", b1=" + l1);
    326         }
    327         int l2 = ((apdu[5] & 0xff) << 8) | (apdu[6] & 0xff);
    328         if (apdu.length == 7) {
    329             // case 2e
    330             this.ne = (l2 == 0) ? 65536 : l2;
    331             return;
    332         }
    333         if (l2 == 0) {
    334             throw new IllegalArgumentException("Invalid APDU: length="
    335                     + apdu.length + ", b1=" + l1 + ", b2||b3=" + l2);
    336         }
    337         if (apdu.length == 4 + 3 + l2) {
    338             // case 3e
    339             this.nc = l2;
    340             this.dataOffset = 7;
    341             return;
    342         } else if (apdu.length == 4 + 5 + l2) {
    343             // case 4e
    344             this.nc = l2;
    345             this.dataOffset = 7;
    346             int leOfs = apdu.length - 2;
    347             int l3 = ((apdu[leOfs] & 0xff) << 8) | (apdu[leOfs + 1] & 0xff);
    348             this.ne = (l3 == 0) ? 65536 : l3;
    349         } else {
    350             throw new IllegalArgumentException("Invalid APDU: length="
    351                     + apdu.length + ", b1=" + l1 + ", b2||b3=" + l2);
    352         }
    353     }
    354
    355     /**
    356      * Constructs a CommandAPDU from the four header bytes, command data,
    357      * and expected response data length. This is case 4 in ISO 7816,
    358      * command data and Le present. The value Nc is taken as
    359      * <code>dataLength</code>.
    360      * If Ne or Nc
    361      * are zero, the APDU is encoded as case 1, 2, or 3 per ISO 7816.
    362      *
    363      * <p>Note that the data bytes are copied to protect against
    364      * subsequent modification.
    365      *
    366      * @param cla the class byte CLA
    367      * @param ins the instruction byte INS
    368      * @param p1 the parameter byte P1
    369      * @param p2 the parameter byte P2
    370      * @param data the byte array containing the data bytes of the command body
    371      * @param dataOffset the offset in the byte array at which the data
    372      *   bytes of the command body begin
    373      * @param dataLength the number of the data bytes in the command body
    374      * @param ne the maximum number of expected data bytes in a response APDU
    375      *
    376      * @throws NullPointerException if data is null and dataLength is not 0
    377      * @throws IllegalArgumentException if dataOffset or dataLength are
    378      *   negative or if dataOffset + dataLength are greater than data.length,
    379      *   or if ne is negative or greater than 65536,
    380      *   or if dataLength is greater than 65535
    381      */
    382     public CommandAPDU(int cla, int ins, int p1, int p2, byte[] data,
    383             int dataOffset, int dataLength, int ne) {
    384         checkArrayBounds(data, dataOffset, dataLength);
    385         if (dataLength > 65535) {
    386             throw new IllegalArgumentException("dataLength is too large");
    387         }
    388         if (ne < 0) {
    389             throw new IllegalArgumentException("ne must not be negative");
    390         }
    391         if (ne > 65536) {
    392             throw new IllegalArgumentException("ne is too large");
    393         }
    394         this.ne = ne;
    395         this.nc = dataLength;
    396         if (dataLength == 0) {
    397             if (ne == 0) {
    398                 // case 1
    399                 this.apdu = new byte[4];
    400                 setHeader(cla, ins, p1, p2);
    401             } else {
    402                 // case 2s or 2e
    403                 if (ne <= 256) {
    404                     // case 2s
    405                     // 256 is encoded as 0x00
    406                     byte len = (ne != 256) ? (byte)ne : 0;
    407                     this.apdu = new byte[5];
    408                     setHeader(cla, ins, p1, p2);
    409                     this.apdu[4] = len;
    410                 } else {
    411                     // case 2e
    412                     byte l1, l2;
    413                     // 65536 is encoded as 0x00 0x00
    414                     if (ne == 65536) {
    415                         l1 = 0;
    416                         l2 = 0;
    417                     } else {
    418                         l1 = (byte)(ne >> 8);
    419                         l2 = (byte)ne;
    420                     }
    421                     this.apdu = new byte[7];
    422                     setHeader(cla, ins, p1, p2);
    423                     this.apdu[5] = l1;
    424                     this.apdu[6] = l2;
    425                 }
    426             }
    427         } else {
    428             if (ne == 0) {
    429                 // case 3s or 3e
    430                 if (dataLength <= 255) {
    431                     // case 3s
    432                     apdu = new byte[4 + 1 + dataLength];
    433                     setHeader(cla, ins, p1, p2);
    434                     apdu[4] = (byte)dataLength;
    435                     this.dataOffset = 5;
    436                     System.arraycopy(data, dataOffset, apdu, 5, dataLength);
    437                 } else {
    438                     // case 3e
    439                     apdu = new byte[4 + 3 + dataLength];
    440                     setHeader(cla, ins, p1, p2);
    441                     apdu[4] = 0;
    442                     apdu[5] = (byte)(dataLength >> 8);
    443                     apdu[6] = (byte)dataLength;
    444                     this.dataOffset = 7;
    445                     System.arraycopy(data, dataOffset, apdu, 7, dataLength);
    446                 }
    447             } else {
    448                 // case 4s or 4e
    449                 if ((dataLength <= 255) && (ne <= 256)) {
    450                     // case 4s
    451                     apdu = new byte[4 + 2 + dataLength];
    452                     setHeader(cla, ins, p1, p2);
    453                     apdu[4] = (byte)dataLength;
    454                     this.dataOffset = 5;
    455                     System.arraycopy(data, dataOffset, apdu, 5, dataLength);
    456                     apdu[apdu.length - 1] = (ne != 256) ? (byte)ne : 0;
    457                 } else {
    458                     // case 4e
    459                     apdu = new byte[4 + 5 + dataLength];
    460                     setHeader(cla, ins, p1, p2);
    461                     apdu[4] = 0;
    462                     apdu[5] = (byte)(dataLength >> 8);
    463                     apdu[6] = (byte)dataLength;
    464                     this.dataOffset = 7;
    465                     System.arraycopy(data, dataOffset, apdu, 7, dataLength);
    466                     if (ne != 65536) {
    467                         int leOfs = apdu.length - 2;
    468                         apdu[leOfs] = (byte)(ne >> 8);
    469                         apdu[leOfs + 1] = (byte)ne;
    470                     } // else le == 65536: no need to fill in, encoded as 0
    471                 }
    472             }
    473         }
    474     }
    475
    476     private void setHeader(int cla, int ins, int p1, int p2) {
    477         apdu[0] = (byte)cla;
    478         apdu[1] = (byte)ins;
    479         apdu[2] = (byte)p1;
    480         apdu[3] = (byte)p2;
    481     }
    482
    483     /**
    484      * Returns the value of the class byte CLA.
    485      *
    486      * @return the value of the class byte CLA.
    487      */
    488     public int getCLA() {
    489         return apdu[0] & 0xff;
    490     }
    491
    492     /**
    493      * Returns the value of the instruction byte INS.
    494      *
    495      * @return the value of the instruction byte INS.
    496      */
    497     public int getINS() {
    498         return apdu[1] & 0xff;
    499     }
    500
    501     /**
    502      * Returns the value of the parameter byte P1.
    503      *
    504      * @return the value of the parameter byte P1.
    505      */
    506     public int getP1() {
    507         return apdu[2] & 0xff;
    508     }
    509
    510     /**
    511      * Returns the value of the parameter byte P2.
    512      *
    513      * @return the value of the parameter byte P2.
    514      */
    515     public int getP2() {
    516         return apdu[3] & 0xff;
    517     }
    518
    519     /**
    520      * Returns the number of data bytes in the command body (Nc) or 0 if this
    521      * APDU has no body. This call is equivalent to
    522      * <code>getData().length</code>.
    523      *
    524      * @return the number of data bytes in the command body or 0 if this APDU
    525      * has no body.
    526      */
    527     public int getNc() {
    528         return nc;
    529     }
    530
    531     /**
    532      * Returns a copy of the data bytes in the command body. If this APDU as
    533      * no body, this method returns a byte array with length zero.
    534      *
    535      * @return a copy of the data bytes in the command body or the empty
    536      *    byte array if this APDU has no body.
    537      */
    538     public byte[] getData() {
    539         byte[] data = new byte[nc];
    540         System.arraycopy(apdu, dataOffset, data, 0, nc);
    541         return data;
    542     }
    543
    544     /**
    545      * Returns the maximum number of expected data bytes in a response
    546      * APDU (Ne).
    547      *
    548      * @return the maximum number of expected data bytes in a response APDU.
    549      */
    550     public int getNe() {
    551         return ne;
    552     }
    553
    554     /**
    555      * Returns a copy of the bytes in this APDU.
    556      *
    557      * @return a copy of the bytes in this APDU.
    558      */
    559     public byte[] getBytes() {
    560         return apdu.clone();
    561     }
    562
    563     /**
    564      * Returns a string representation of this command APDU.
    565      *
    566      * @return a String representation of this command APDU.
    567      */
    568     public String toString() {
    569         return "CommmandAPDU: " + apdu.length + " bytes, nc=" + nc + ", ne=" + ne;
    570     }
    571
    572     /**
    573      * Compares the specified object with this command APDU for equality.
    574      * Returns true if the given object is also a CommandAPDU and its bytes are
    575      * identical to the bytes in this CommandAPDU.
    576      *
    577      * @param obj the object to be compared for equality with this command APDU
    578      * @return true if the specified object is equal to this command APDU
    579      */
    580     public boolean equals(Object obj) {
    581         if (this == obj) {
    582             return true;
    583         }
    584         if (obj instanceof CommandAPDU == false) {
    585             return false;
    586         }
    587         CommandAPDU other = (CommandAPDU)obj;
    588         return Arrays.equals(this.apdu, other.apdu);
    589      }
    590
    591     /**
    592      * Returns the hash code value for this command APDU.
    593      *
    594      * @return the hash code value for this command APDU.
    595      */
    596     public int hashCode() {
    597         return Arrays.hashCode(apdu);
    598     }
    599
    600
    601     /**
    602      * Restores the state of this object from the stream.
    603      *
    604      * @param  in the {@code ObjectInputStream} from which data is read
    605      * @throws IOException if an I/O error occurs
    606      * @throws ClassNotFoundException if a serialized class cannot be loaded
    607      */
    608     private void readObject(java.io.ObjectInputStream in)
    609             throws IOException, ClassNotFoundException {
    610         apdu = (byte[])in.readUnshared();
    611         // initialize transient fields
    612         parse();
    613     }
    614
    615 }