1 /* iso7816.c - ISO 7816 commands
2 * Copyright (C) 2003, 2004, 2008, 2009 Free Software Foundation, Inc.
4 * This file is part of GnuPG.
6 * GnuPG is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * GnuPG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
28 #if defined(GNUPG_SCD_MAIN_HEADER)
29 #include GNUPG_SCD_MAIN_HEADER
30 #elif GNUPG_MAJOR_VERSION == 1
31 /* This is used with GnuPG version < 1.9. The code has been source
32 copied from the current GnuPG >= 1.9 and is maintained over
39 #else /* GNUPG_MAJOR_VERSION != 1 */
41 #endif /* GNUPG_MAJOR_VERSION != 1 */
47 #define CMD_SELECT_FILE 0xA4
48 #define CMD_VERIFY ISO7816_VERIFY
49 #define CMD_CHANGE_REFERENCE_DATA ISO7816_CHANGE_REFERENCE_DATA
50 #define CMD_RESET_RETRY_COUNTER ISO7816_RESET_RETRY_COUNTER
51 #define CMD_GET_DATA 0xCA
52 #define CMD_PUT_DATA 0xDA
55 #define CMD_INTERNAL_AUTHENTICATE 0x88
56 #define CMD_GENERATE_KEYPAIR 0x47
57 #define CMD_GET_CHALLENGE 0x84
58 #define CMD_READ_BINARY 0xB0
59 #define CMD_READ_RECORD 0xB2
68 case SW_EEPROM_FAILURE
: ec
= GPG_ERR_HARDWARE
; break;
69 case SW_TERM_STATE
: ec
= GPG_ERR_CARD
; break;
70 case SW_WRONG_LENGTH
: ec
= GPG_ERR_INV_VALUE
; break;
71 case SW_SM_NOT_SUP
: ec
= GPG_ERR_NOT_SUPPORTED
; break;
72 case SW_CC_NOT_SUP
: ec
= GPG_ERR_NOT_SUPPORTED
; break;
73 case SW_CHV_WRONG
: ec
= GPG_ERR_BAD_PIN
; break;
74 case SW_CHV_BLOCKED
: ec
= GPG_ERR_PIN_BLOCKED
; break;
75 case SW_USE_CONDITIONS
: ec
= GPG_ERR_USE_CONDITIONS
; break;
76 case SW_NOT_SUPPORTED
: ec
= GPG_ERR_NOT_SUPPORTED
; break;
77 case SW_BAD_PARAMETER
: ec
= GPG_ERR_INV_VALUE
; break;
78 case SW_FILE_NOT_FOUND
: ec
= GPG_ERR_ENOENT
; break;
79 case SW_RECORD_NOT_FOUND
:ec
= GPG_ERR_NOT_FOUND
; break;
80 case SW_REF_NOT_FOUND
: ec
= GPG_ERR_NO_OBJ
; break;
81 case SW_BAD_P0_P1
: ec
= GPG_ERR_INV_VALUE
; break;
82 case SW_EXACT_LENGTH
: ec
= GPG_ERR_INV_VALUE
; break;
83 case SW_INS_NOT_SUP
: ec
= GPG_ERR_CARD
; break;
84 case SW_CLA_NOT_SUP
: ec
= GPG_ERR_CARD
; break;
85 case SW_SUCCESS
: ec
= 0; break;
87 case SW_HOST_OUT_OF_CORE
: ec
= GPG_ERR_ENOMEM
; break;
88 case SW_HOST_INV_VALUE
: ec
= GPG_ERR_INV_VALUE
; break;
89 case SW_HOST_INCOMPLETE_CARD_RESPONSE
: ec
= GPG_ERR_CARD
; break;
90 case SW_HOST_NOT_SUPPORTED
: ec
= GPG_ERR_NOT_SUPPORTED
; break;
91 case SW_HOST_LOCKING_FAILED
: ec
= GPG_ERR_BUG
; break;
92 case SW_HOST_BUSY
: ec
= GPG_ERR_EBUSY
; break;
93 case SW_HOST_NO_CARD
: ec
= GPG_ERR_CARD_NOT_PRESENT
; break;
94 case SW_HOST_CARD_INACTIVE
: ec
= GPG_ERR_CARD_RESET
; break;
95 case SW_HOST_CARD_IO_ERROR
: ec
= GPG_ERR_EIO
; break;
96 case SW_HOST_GENERAL_ERROR
: ec
= GPG_ERR_GENERAL
; break;
97 case SW_HOST_NO_READER
: ec
= GPG_ERR_ENODEV
; break;
98 case SW_HOST_ABORTED
: ec
= GPG_ERR_CANCELED
; break;
99 case SW_HOST_NO_KEYPAD
: ec
= GPG_ERR_NOT_SUPPORTED
; break;
103 ec
= GPG_ERR_GENERAL
; /* Should not happen. */
104 else if ((sw
& 0xff00) == SW_MORE_DATA
)
105 ec
= 0; /* This should actually never been seen here. */
109 return gpg_error (ec
);
112 /* Map a status word from the APDU layer to a gpg-error code. */
114 iso7816_map_sw (int sw
)
116 /* All APDU functions should return 0x9000 on success but for
117 historical reasons of the implementation some return 0 to
118 indicate success. We allow for that here. */
119 return sw
? map_sw (sw
) : 0;
123 /* This function is specialized version of the SELECT FILE command.
124 SLOT is the card and reader as created for example by
125 apdu_open_reader (), AID is a buffer of size AIDLEN holding the
126 requested application ID. The function can't be used to enumerate
127 AIDs and won't return the AID on success. The return value is 0
128 for okay or a GPG error code. Note that ISO error codes are
129 internally mapped. Bit 0 of FLAGS should be set if the card does
130 not understand P2=0xC0. */
132 iso7816_select_application (int slot
, const char *aid
, size_t aidlen
,
136 sw
= apdu_send_simple (slot
, 0, 0x00, CMD_SELECT_FILE
, 4,
137 (flags
&1)? 0 :0x0c, aidlen
, aid
);
143 iso7816_select_file (int slot
, int tag
, int is_dir
,
144 unsigned char **result
, size_t *resultlen
)
147 unsigned char tagbuf
[2];
149 tagbuf
[0] = (tag
>> 8) & 0xff;
150 tagbuf
[1] = tag
& 0xff;
152 if (result
|| resultlen
)
156 return gpg_error (GPG_ERR_NOT_IMPLEMENTED
);
160 p0
= (tag
== 0x3F00)? 0: is_dir
? 1:2;
161 p1
= 0x0c; /* No FC return. */
162 sw
= apdu_send_simple (slot
, 0, 0x00, CMD_SELECT_FILE
,
163 p0
, p1
, 2, (char*)tagbuf
);
171 /* Do a select file command with a direct path. */
173 iso7816_select_path (int slot
, const unsigned short *path
, size_t pathlen
,
174 unsigned char **result
, size_t *resultlen
)
177 unsigned char buffer
[100];
180 if (result
|| resultlen
)
184 return gpg_error (GPG_ERR_NOT_IMPLEMENTED
);
187 if (pathlen
/2 >= sizeof buffer
)
188 return gpg_error (GPG_ERR_TOO_LARGE
);
190 for (buflen
= 0; pathlen
; pathlen
--, path
++)
192 buffer
[buflen
++] = (*path
>> 8);
193 buffer
[buflen
++] = *path
;
197 p1
= 0x0c; /* No FC return. */
198 sw
= apdu_send_simple (slot
, 0, 0x00, CMD_SELECT_FILE
,
199 p0
, p1
, buflen
, (char*)buffer
);
204 /* This is a private command currently only working for TCOS cards. */
206 iso7816_list_directory (int slot
, int list_dirs
,
207 unsigned char **result
, size_t *resultlen
)
211 if (!result
|| !resultlen
)
212 return gpg_error (GPG_ERR_INV_VALUE
);
216 sw
= apdu_send (slot
, 0, 0x80, 0xAA, list_dirs
? 1:2, 0, -1, NULL
,
218 if (sw
!= SW_SUCCESS
)
220 /* Make sure that pending buffers are released. */
229 /* This funcion sends an already formatted APDU to the card. With
230 HANDLE_MORE set to true a MORE DATA status will be handled
231 internally. The return value is a gpg error code (i.e. a mapped
232 status word). This is basically the same as apdu_send_direct but
233 it maps the status word and does not return it in the result
236 iso7816_apdu_direct (int slot
, const void *apdudata
, size_t apdudatalen
,
238 unsigned char **result
, size_t *resultlen
)
242 if (!result
|| !resultlen
)
243 return gpg_error (GPG_ERR_INV_VALUE
);
247 sw
= apdu_send_direct (slot
, 0, apdudata
, apdudatalen
, handle_more
,
252 sw
= SW_HOST_GENERAL_ERROR
;
255 sw
= ((*result
)[*resultlen
-2] << 8) | (*result
)[*resultlen
-1];
260 if (sw
!= SW_SUCCESS
)
262 /* Make sure that pending buffers are released. */
271 /* Check whether the reader supports the ISO command code COMMAND on
272 the keypad. Returns 0 on success. */
274 iso7816_check_keypad (int slot
, int command
, iso7816_pininfo_t
*pininfo
)
278 sw
= apdu_check_keypad (slot
, command
,
279 pininfo
->mode
, pininfo
->minlen
, pininfo
->maxlen
,
281 return iso7816_map_sw (sw
);
285 /* Perform a VERIFY command on SLOT using the card holder verification
286 vector CHVNO with a CHV of lenght CHVLEN. With PININFO non-NULL
287 the keypad of the reader will be used. Returns 0 on success. */
289 iso7816_verify_kp (int slot
, int chvno
, const char *chv
, size_t chvlen
,
290 iso7816_pininfo_t
*pininfo
)
294 if (pininfo
&& pininfo
->mode
)
295 sw
= apdu_send_simple_kp (slot
, 0x00, CMD_VERIFY
, 0, chvno
, chvlen
, chv
,
301 sw
= apdu_send_simple (slot
, 0, 0x00, CMD_VERIFY
, 0, chvno
, chvlen
, chv
);
305 /* Perform a VERIFY command on SLOT using the card holder verification
306 vector CHVNO with a CHV of lenght CHVLEN. Returns 0 on success. */
308 iso7816_verify (int slot
, int chvno
, const char *chv
, size_t chvlen
)
310 return iso7816_verify_kp (slot
, chvno
, chv
, chvlen
, NULL
);
313 /* Perform a CHANGE_REFERENCE_DATA command on SLOT for the card holder
314 verification vector CHVNO. If the OLDCHV is NULL (and OLDCHVLEN
315 0), a "change reference data" is done, otherwise an "exchange
316 reference data". The new reference data is expected in NEWCHV of
317 length NEWCHVLEN. With PININFO non-NULL the keypad of the reader
320 iso7816_change_reference_data_kp (int slot
, int chvno
,
321 const char *oldchv
, size_t oldchvlen
,
322 const char *newchv
, size_t newchvlen
,
323 iso7816_pininfo_t
*pininfo
)
328 if ((!oldchv
&& oldchvlen
)
329 || (oldchv
&& !oldchvlen
)
330 || !newchv
|| !newchvlen
)
331 return gpg_error (GPG_ERR_INV_VALUE
);
333 buf
= xtrymalloc (oldchvlen
+ newchvlen
);
335 return gpg_error (gpg_err_code_from_errno (errno
));
337 memcpy (buf
, oldchv
, oldchvlen
);
338 memcpy (buf
+oldchvlen
, newchv
, newchvlen
);
340 if (pininfo
&& pininfo
->mode
)
341 sw
= apdu_send_simple_kp (slot
, 0x00, CMD_CHANGE_REFERENCE_DATA
,
342 oldchvlen
? 0 : 1, chvno
, oldchvlen
+newchvlen
, buf
,
348 sw
= apdu_send_simple (slot
, 0, 0x00, CMD_CHANGE_REFERENCE_DATA
,
349 oldchvlen
? 0 : 1, chvno
, oldchvlen
+newchvlen
, buf
);
355 /* Perform a CHANGE_REFERENCE_DATA command on SLOT for the card holder
356 verification vector CHVNO. If the OLDCHV is NULL (and OLDCHVLEN
357 0), a "change reference data" is done, otherwise an "exchange
358 reference data". The new reference data is expected in NEWCHV of
361 iso7816_change_reference_data (int slot
, int chvno
,
362 const char *oldchv
, size_t oldchvlen
,
363 const char *newchv
, size_t newchvlen
)
365 return iso7816_change_reference_data_kp (slot
, chvno
, oldchv
, oldchvlen
,
366 newchv
, newchvlen
, NULL
);
371 iso7816_reset_retry_counter_kp (int slot
, int chvno
,
372 const char *newchv
, size_t newchvlen
,
373 iso7816_pininfo_t
*pininfo
)
377 if (!newchv
|| !newchvlen
)
378 return gpg_error (GPG_ERR_INV_VALUE
);
380 /* FIXME: The keypad mode has not yet been tested. */
381 if (pininfo
&& pininfo
->mode
)
382 sw
= apdu_send_simple_kp (slot
, 0x00, CMD_RESET_RETRY_COUNTER
,
383 2, chvno
, newchvlen
, newchv
,
389 sw
= apdu_send_simple (slot
, 0, 0x00, CMD_RESET_RETRY_COUNTER
,
390 2, chvno
, newchvlen
, newchv
);
396 iso7816_reset_retry_counter_with_rc (int slot
, int chvno
,
397 const char *data
, size_t datalen
)
401 if (!data
|| !datalen
)
402 return gpg_error (GPG_ERR_INV_VALUE
);
404 sw
= apdu_send_simple (slot
, 0, 0x00, CMD_RESET_RETRY_COUNTER
,
405 0, chvno
, datalen
, data
);
411 iso7816_reset_retry_counter (int slot
, int chvno
,
412 const char *newchv
, size_t newchvlen
)
414 return iso7816_reset_retry_counter_kp (slot
, chvno
, newchv
, newchvlen
, NULL
);
419 /* Perform a GET DATA command requesting TAG and storing the result in
420 a newly allocated buffer at the address passed by RESULT. Return
421 the length of this data at the address of RESULTLEN. */
423 iso7816_get_data (int slot
, int tag
,
424 unsigned char **result
, size_t *resultlen
)
428 if (!result
|| !resultlen
)
429 return gpg_error (GPG_ERR_INV_VALUE
);
433 sw
= apdu_send (slot
, 0, 0x00, CMD_GET_DATA
,
434 ((tag
>> 8) & 0xff), (tag
& 0xff), -1, NULL
,
436 if (sw
!= SW_SUCCESS
)
438 /* Make sure that pending buffers are released. */
449 /* Perform a PUT DATA command on card in SLOT. Write DATA of length
450 DATALEN to TAG. EXTENDED_MODE controls whether extended length
451 headers or command chaining is used instead of single length
454 iso7816_put_data (int slot
, int extended_mode
, int tag
,
455 const unsigned char *data
, size_t datalen
)
459 sw
= apdu_send_simple (slot
, extended_mode
, 0x00, CMD_PUT_DATA
,
460 ((tag
>> 8) & 0xff), (tag
& 0xff),
461 datalen
, (const char*)data
);
465 /* Same as iso7816_put_data but uses an odd instruction byte. */
467 iso7816_put_data_odd (int slot
, int extended_mode
, int tag
,
468 const unsigned char *data
, size_t datalen
)
472 sw
= apdu_send_simple (slot
, extended_mode
, 0x00, CMD_PUT_DATA
+1,
473 ((tag
>> 8) & 0xff), (tag
& 0xff),
474 datalen
, (const char*)data
);
478 /* Manage Security Environment. This is a weird operation and there
479 is no easy abstraction for it. Furthermore, some card seem to have
480 a different interpreation of 7816-8 and thus we resort to let the
481 caller decide what to do. */
483 iso7816_manage_security_env (int slot
, int p1
, int p2
,
484 const unsigned char *data
, size_t datalen
)
488 if (p1
< 0 || p1
> 255 || p2
< 0 || p2
> 255 )
489 return gpg_error (GPG_ERR_INV_VALUE
);
491 sw
= apdu_send_simple (slot
, 0, 0x00, CMD_MSE
, p1
, p2
,
492 data
? datalen
: -1, (const char*)data
);
497 /* Perform the security operation COMPUTE DIGITAL SIGANTURE. On
498 success 0 is returned and the data is availavle in a newly
499 allocated buffer stored at RESULT with its length stored at
502 iso7816_compute_ds (int slot
, const unsigned char *data
, size_t datalen
,
503 unsigned char **result
, size_t *resultlen
)
507 if (!data
|| !datalen
|| !result
|| !resultlen
)
508 return gpg_error (GPG_ERR_INV_VALUE
);
512 sw
= apdu_send (slot
, 0,
513 0x00, CMD_PSO
, 0x9E, 0x9A, datalen
, (const char*)data
,
515 if (sw
!= SW_SUCCESS
)
517 /* Make sure that pending buffers are released. */
528 /* Perform the security operation DECIPHER. PADIND is the padding
529 indicator to be used. It should be 0 if no padding is required, a
530 value of -1 suppresses the padding byte. On success 0 is returned
531 and the plaintext is available in a newly allocated buffer stored
532 at RESULT with its length stored at RESULTLEN. */
534 iso7816_decipher (int slot
, int extended_mode
,
535 const unsigned char *data
, size_t datalen
,
536 int padind
, unsigned char **result
, size_t *resultlen
)
541 if (!data
|| !datalen
|| !result
|| !resultlen
)
542 return gpg_error (GPG_ERR_INV_VALUE
);
548 /* We need to prepend the padding indicator. */
549 buf
= xtrymalloc (datalen
+ 1);
551 return gpg_error (gpg_err_code_from_errno (errno
));
553 *buf
= padind
; /* Padding indicator. */
554 memcpy (buf
+1, data
, datalen
);
555 sw
= apdu_send (slot
, extended_mode
,
556 0x00, CMD_PSO
, 0x80, 0x86,
557 datalen
+1, (char*)buf
,
563 sw
= apdu_send (slot
, extended_mode
,
564 0x00, CMD_PSO
, 0x80, 0x86,
565 datalen
, (const char *)data
,
568 if (sw
!= SW_SUCCESS
)
570 /* Make sure that pending buffers are released. */
582 iso7816_internal_authenticate (int slot
,
583 const unsigned char *data
, size_t datalen
,
584 unsigned char **result
, size_t *resultlen
)
588 if (!data
|| !datalen
|| !result
|| !resultlen
)
589 return gpg_error (GPG_ERR_INV_VALUE
);
593 sw
= apdu_send (slot
, 0, 0x00, CMD_INTERNAL_AUTHENTICATE
, 0, 0,
594 datalen
, (const char*)data
, result
, resultlen
);
595 if (sw
!= SW_SUCCESS
)
597 /* Make sure that pending buffers are released. */
608 /* LE is the expected return length. This is usually 0 except if
609 extended length mode is used and more than 256 byte will be
610 returned. In that case a value of -1 uses a large default
611 (e.g. 4096 bytes), a value larger 256 used that value. */
613 do_generate_keypair (int slot
, int extended_mode
, int readonly
,
614 const unsigned char *data
, size_t datalen
,
616 unsigned char **result
, size_t *resultlen
)
620 if (!data
|| !datalen
|| !result
|| !resultlen
)
621 return gpg_error (GPG_ERR_INV_VALUE
);
625 sw
= apdu_send_le (slot
, extended_mode
,
626 0x00, CMD_GENERATE_KEYPAIR
, readonly
? 0x81:0x80, 0,
627 datalen
, (const char*)data
,
628 le
>= 0 && le
< 256? 256:le
,
630 if (sw
!= SW_SUCCESS
)
632 /* Make sure that pending buffers are released. */
644 iso7816_generate_keypair (int slot
, int extended_mode
,
645 const unsigned char *data
, size_t datalen
,
647 unsigned char **result
, size_t *resultlen
)
649 return do_generate_keypair (slot
, extended_mode
, 0,
650 data
, datalen
, le
, result
, resultlen
);
655 iso7816_read_public_key (int slot
, int extended_mode
,
656 const unsigned char *data
, size_t datalen
,
658 unsigned char **result
, size_t *resultlen
)
660 return do_generate_keypair (slot
, extended_mode
, 1,
661 data
, datalen
, le
, result
, resultlen
);
667 iso7816_get_challenge (int slot
, int length
, unsigned char *buffer
)
670 unsigned char *result
;
673 if (!buffer
|| length
< 1)
674 return gpg_error (GPG_ERR_INV_VALUE
);
679 n
= length
> 254? 254 : length
;
680 sw
= apdu_send_le (slot
, 0,
681 0x00, CMD_GET_CHALLENGE
, 0, 0, -1, NULL
, n
,
682 &result
, &resultlen
);
683 if (sw
!= SW_SUCCESS
)
685 /* Make sure that pending buffers are released. */
691 memcpy (buffer
, result
, resultlen
);
701 /* Perform a READ BINARY command requesting a maximum of NMAX bytes
702 from OFFSET. With NMAX = 0 the entire file is read. The result is
703 stored in a newly allocated buffer at the address passed by RESULT.
704 Returns the length of this data at the address of RESULTLEN. */
706 iso7816_read_binary (int slot
, size_t offset
, size_t nmax
,
707 unsigned char **result
, size_t *resultlen
)
710 unsigned char *buffer
;
712 int read_all
= !nmax
;
715 if (!result
|| !resultlen
)
716 return gpg_error (GPG_ERR_INV_VALUE
);
720 /* We can only encode 15 bits in p0,p1 to indicate an offset. Thus
721 we check for this limit. */
723 return gpg_error (GPG_ERR_INV_VALUE
);
729 n
= read_all
? 0 : nmax
;
730 sw
= apdu_send_le (slot
, 0, 0x00, CMD_READ_BINARY
,
731 ((offset
>>8) & 0xff), (offset
& 0xff) , -1, NULL
,
732 n
, &buffer
, &bufferlen
);
733 if ( SW_EXACT_LENGTH_P(sw
) )
736 sw
= apdu_send_le (slot
, 0, 0x00, CMD_READ_BINARY
,
737 ((offset
>>8) & 0xff), (offset
& 0xff) , -1, NULL
,
738 n
, &buffer
, &bufferlen
);
741 if (*result
&& sw
== SW_BAD_P0_P1
)
743 /* Bad Parameter means that the offset is outside of the
744 EF. When reading all data we take this as an indication
749 if (sw
!= SW_SUCCESS
&& sw
!= SW_EOF_REACHED
)
751 /* Make sure that pending buffers are released. */
758 if (*result
) /* Need to extend the buffer. */
760 unsigned char *p
= xtryrealloc (*result
, *resultlen
+ bufferlen
);
763 gpg_error_t err
= gpg_error_from_syserror ();
771 memcpy (*result
+ *resultlen
, buffer
, bufferlen
);
772 *resultlen
+= bufferlen
;
776 else /* Transfer the buffer into our result. */
779 *resultlen
= bufferlen
;
783 break; /* We simply truncate the result for too large
785 if (nmax
> bufferlen
)
790 while ((read_all
&& sw
!= SW_EOF_REACHED
) || (!read_all
&& nmax
));
795 /* Perform a READ RECORD command. RECNO gives the record number to
796 read with 0 indicating the current record. RECCOUNT must be 1 (not
797 all cards support reading of more than one record). SHORT_EF
798 should be 0 to read the current EF or contain a short EF. The
799 result is stored in a newly allocated buffer at the address passed
800 by RESULT. Returns the length of this data at the address of
803 iso7816_read_record (int slot
, int recno
, int reccount
, int short_ef
,
804 unsigned char **result
, size_t *resultlen
)
807 unsigned char *buffer
;
810 if (!result
|| !resultlen
)
811 return gpg_error (GPG_ERR_INV_VALUE
);
815 /* We can only encode 15 bits in p0,p1 to indicate an offset. Thus
816 we check for this limit. */
817 if (recno
< 0 || recno
> 255 || reccount
!= 1
818 || short_ef
< 0 || short_ef
> 254 )
819 return gpg_error (GPG_ERR_INV_VALUE
);
823 sw
= apdu_send_le (slot
, 0, 0x00, CMD_READ_RECORD
,
825 short_ef
? short_ef
: 0x04,
827 0, &buffer
, &bufferlen
);
829 if (sw
!= SW_SUCCESS
&& sw
!= SW_EOF_REACHED
)
831 /* Make sure that pending buffers are released. */
839 *resultlen
= bufferlen
;