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      */
CommandAPDU(byte[] apdu)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      */
CommandAPDU(byte[] apdu, int apduOffset, int apduLength)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 
checkArrayBounds(byte[] b, int ofs, int len)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      */
CommandAPDU(ByteBuffer apdu)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      */
CommandAPDU(int cla, int ins, int p1, int p2)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      */
CommandAPDU(int cla, int ins, int p1, int p2, int ne)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      */
CommandAPDU(int cla, int ins, int p1, int p2, byte[] data)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      */
CommandAPDU(int cla, int ins, int p1, int p2, byte[] data, int dataOffset, int dataLength)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      */
CommandAPDU(int cla, int ins, int p1, int p2, byte[] data, int ne)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 
arrayLength(byte[] b)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      */
parse()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      */
CommandAPDU(int cla, int ins, int p1, int p2, byte[] data, int dataOffset, int dataLength, int ne)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 
setHeader(int cla, int ins, int p1, int p2)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      */
getCLA()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      */
getINS()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      */
getP1()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      */
getP2()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      */
getNc()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      */
getData()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      */
getNe()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      */
getBytes()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      */
toString()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      */
equals(Object obj)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      */
hashCode()595     public int hashCode() {
596         return Arrays.hashCode(apdu);
597     }
598 
readObject(java.io.ObjectInputStream in)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 }
607