You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

220 lines
7.1 KiB

  1. From d8f63eb6fcc1441c12a44850da2fa22a6fe81634 Mon Sep 17 00:00:00 2001
  2. From: =?UTF-8?q?Nguy=E1=BB=85n=20H=E1=BB=93ng=20Qu=C3=A2n?=
  3. <ng.hong.quan@gmail.com>
  4. Date: Thu, 11 Apr 2013 11:47:51 +0700
  5. Subject: [PATCH 12/18] OpenPGP: Support write certificate for Gnuk.
  6. ---
  7. src/libopensc/card-openpgp.c | 158 +++++++++++++++++++++++++++++++++----------
  8. 1 file changed, 123 insertions(+), 35 deletions(-)
  9. diff --git a/src/libopensc/card-openpgp.c b/src/libopensc/card-openpgp.c
  10. index 8a1a270..d9db948 100644
  11. --- a/src/libopensc/card-openpgp.c
  12. +++ b/src/libopensc/card-openpgp.c
  13. @@ -725,6 +725,8 @@ pgp_iterate_blobs(struct blob *blob, int level, void (*func)())
  14. static int
  15. pgp_read_blob(sc_card_t *card, struct blob *blob)
  16. {
  17. + struct pgp_priv_data *priv = DRVDATA (card);
  18. +
  19. if (blob->data != NULL)
  20. return SC_SUCCESS;
  21. if (blob->info == NULL)
  22. @@ -735,6 +737,11 @@ pgp_read_blob(sc_card_t *card, struct blob *blob)
  23. size_t buf_len = (card->caps & SC_CARD_CAP_APDU_EXT)
  24. ? sizeof(buffer) : 256;
  25. + /* Buffer length for certificate */
  26. + if (blob->id == DO_CERT && priv->max_cert_size > 0) {
  27. + buf_len = MIN(priv->max_cert_size, sizeof(buffer));
  28. + }
  29. +
  30. /* Buffer length for Gnuk pubkey */
  31. if (card->type == SC_CARD_TYPE_OPENPGP_GNUK &&
  32. (blob->id == 0xa400 || blob->id == 0xb600 || blob->id == 0xb800
  33. @@ -1190,49 +1197,75 @@ pgp_get_data(sc_card_t *card, unsigned int tag, u8 *buf, size_t buf_len)
  34. LOG_FUNC_RETURN(card->ctx, apdu.resplen);
  35. }
  36. -/* ABI: PUT DATA */
  37. -static int
  38. -pgp_put_data(sc_card_t *card, unsigned int tag, const u8 *buf, size_t buf_len)
  39. +
  40. +/* Internal: Write certificate for Gnuk */
  41. +static int gnuk_write_certificate(sc_card_t *card, const u8 *buf, size_t length)
  42. {
  43. + sc_context_t *ctx = card->ctx;
  44. + size_t i = 0;
  45. sc_apdu_t apdu;
  46. + u8 *part;
  47. + size_t plen;
  48. + int r = SC_SUCCESS;
  49. +
  50. + LOG_FUNC_CALLED(ctx);
  51. +
  52. + /* If null data is passed, delete certificate */
  53. + if (buf == NULL || length == 0) {
  54. + sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0xD6, 0x85, 0);
  55. + r = sc_transmit_apdu(card, &apdu);
  56. + LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
  57. + /* Check response */
  58. + r = sc_check_sw(card, apdu.sw1, apdu.sw2);
  59. + LOG_FUNC_RETURN(card->ctx, length);
  60. + }
  61. +
  62. + /* Ref: gnuk_put_binary_libusb.py and gnuk_token.py in Gnuk source tree */
  63. + /* Split data to segments of 256 bytes. Send each segment via command chaining,
  64. + * with particular P1 byte for each segment */
  65. + while (i*256 < length) {
  66. + part = (u8 *)buf + i*256;
  67. + plen = MIN(length - i*256, 256);
  68. +
  69. + sc_log(card->ctx, "Write part %d from offset 0x%X, len %d", i+1, part, plen);
  70. +
  71. + if (i == 0) {
  72. + sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xD6, 0x85, 0);
  73. + }
  74. + else {
  75. + sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xD6, i, 0);
  76. + }
  77. + apdu.flags |= SC_APDU_FLAGS_CHAINING;
  78. + apdu.data = part;
  79. + apdu.datalen = apdu.lc = plen;
  80. +
  81. + r = sc_transmit_apdu(card, &apdu);
  82. + LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
  83. + /* Check response */
  84. + r = sc_check_sw(card, apdu.sw1, apdu.sw2);
  85. + LOG_TEST_RET(card->ctx, r, "UPDATE BINARY returned error");
  86. +
  87. + /* To next part */
  88. + i++;
  89. + }
  90. + LOG_FUNC_RETURN(card->ctx, length);
  91. +}
  92. +
  93. +
  94. +/* Internal: Use PUT DATA command to write */
  95. +static int
  96. +pgp_put_data_plain(sc_card_t *card, unsigned int tag, const u8 *buf, size_t buf_len)
  97. +{
  98. struct pgp_priv_data *priv = DRVDATA(card);
  99. - struct blob *affected_blob = NULL;
  100. - struct do_info *dinfo = NULL;
  101. + sc_context_t *ctx = card->ctx;
  102. + sc_apdu_t apdu;
  103. u8 ins = 0xDA;
  104. u8 p1 = tag >> 8;
  105. u8 p2 = tag & 0xFF;
  106. u8 apdu_case = SC_APDU_CASE_3;
  107. int r;
  108. - LOG_FUNC_CALLED(card->ctx);
  109. -
  110. - /* Check if the tag is writable */
  111. - affected_blob = pgp_find_blob(card, tag);
  112. -
  113. - /* Non-readable DOs have no represented blob, we have to check from pgp_get_info_by_tag */
  114. - if (affected_blob == NULL)
  115. - dinfo = pgp_get_info_by_tag(card, tag);
  116. - else
  117. - dinfo = affected_blob->info;
  118. -
  119. - if (dinfo == NULL) {
  120. - sc_log(card->ctx, "The DO %04X does not exist.", tag);
  121. - LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
  122. - }
  123. - else if ((dinfo->access & WRITE_MASK) == WRITE_NEVER) {
  124. - sc_log(card->ctx, "DO %04X is not writable.", tag);
  125. - LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_ALLOWED);
  126. - }
  127. -
  128. - /* Check data size.
  129. - * We won't check other DOs than 7F21 (certificate), because their capacity
  130. - * is hard-codded and may change in various version of the card. If we check here,
  131. - * the driver may be sticked to a limit version number of card.
  132. - * 7F21 size is soft-coded, so we can check it. */
  133. - if (tag == DO_CERT && buf_len > priv->max_cert_size) {
  134. - sc_log(card->ctx, "Data size %ld exceeds DO size limit %ld.", buf_len, priv->max_cert_size);
  135. - LOG_FUNC_RETURN(card->ctx, SC_ERROR_WRONG_LENGTH);
  136. - }
  137. + LOG_FUNC_CALLED(ctx);
  138. /* Extended Header list (004D DO) needs a variant of PUT DATA command */
  139. if (tag == 0x004D) {
  140. @@ -1258,15 +1291,70 @@ pgp_put_data(sc_card_t *card, unsigned int tag, const u8 *buf, size_t buf_len)
  141. apdu.lc = buf_len;
  142. }
  143. else {
  144. + /* This case is to empty DO */
  145. sc_format_apdu(card, &apdu, SC_APDU_CASE_1, ins, p1, p2);
  146. }
  147. /* Send APDU to card */
  148. r = sc_transmit_apdu(card, &apdu);
  149. - LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
  150. + LOG_TEST_RET(ctx, r, "APDU transmit failed");
  151. /* Check response */
  152. r = sc_check_sw(card, apdu.sw1, apdu.sw2);
  153. + if (r < 0)
  154. + LOG_FUNC_RETURN(ctx, r);
  155. +
  156. + LOG_FUNC_RETURN(ctx, buf_len);
  157. +}
  158. +
  159. +/* ABI: PUT DATA */
  160. +static int
  161. +pgp_put_data(sc_card_t *card, unsigned int tag, const u8 *buf, size_t buf_len)
  162. +{
  163. + struct pgp_priv_data *priv = DRVDATA(card);
  164. + struct blob *affected_blob = NULL;
  165. + struct do_info *dinfo = NULL;
  166. + int r;
  167. +
  168. + LOG_FUNC_CALLED(card->ctx);
  169. +
  170. + /* Check if the tag is writable */
  171. + if (priv->current->id != tag)
  172. + affected_blob = pgp_find_blob(card, tag);
  173. +
  174. + /* Non-readable DOs have no represented blob, we have to check from pgp_get_info_by_tag */
  175. + if (affected_blob == NULL)
  176. + dinfo = pgp_get_info_by_tag(card, tag);
  177. + else
  178. + dinfo = affected_blob->info;
  179. +
  180. + if (dinfo == NULL) {
  181. + sc_log(card->ctx, "The DO %04X does not exist.", tag);
  182. + LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
  183. + }
  184. + else if ((dinfo->access & WRITE_MASK) == WRITE_NEVER) {
  185. + sc_log(card->ctx, "DO %04X is not writable.", tag);
  186. + LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_ALLOWED);
  187. + }
  188. +
  189. + /* Check data size.
  190. + * We won't check other DOs than 7F21 (certificate), because their capacity
  191. + * is hard-codded and may change in various version of the card. If we check here,
  192. + * the driver may be sticked to a limit version number of card.
  193. + * 7F21 size is soft-coded, so we can check it. */
  194. + if (tag == DO_CERT && buf_len > priv->max_cert_size) {
  195. + sc_log(card->ctx, "Data size %ld exceeds DO size limit %ld.", buf_len, priv->max_cert_size);
  196. + LOG_FUNC_RETURN(card->ctx, SC_ERROR_WRONG_LENGTH);
  197. + }
  198. +
  199. + if (tag == DO_CERT && card->type == SC_CARD_TYPE_OPENPGP_GNUK) {
  200. + /* Gnuk need a special way to write certificate. */
  201. + r = gnuk_write_certificate(card, buf, buf_len);
  202. + }
  203. + else {
  204. + r = pgp_put_data_plain(card, tag, buf, buf_len);
  205. + }
  206. +
  207. /* Instruct more in case of error */
  208. if (r == SC_ERROR_SECURITY_STATUS_NOT_SATISFIED) {
  209. sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Please verify PIN first.");
  210. --
  211. 1.9.3