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

    599     private void readObject(java.io.ObjectInputStream in)
    600             throws java.io.IOException, ClassNotFoundException {
    601         apdu = (byte[])in.readUnshared();
    602         // initialize transient fields
    603         parse();
    604     }
    605
    606 }
    --- EOF ---