"Fossies" - the Fresh Open Source Software Archive

Member "opensc-0.22.0/src/tools/piv-tool.c" (10 Aug 2021, 15726 Bytes) of package /linux/privat/opensc-0.22.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "piv-tool.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 0.21.0_vs_0.22.0.

    1 /*
    2  * piv-tool.c: Tool for accessing smart cards with libopensc
    3  *
    4  * Copyright (C) 2001  Juha Yrjölä <juha.yrjola@iki.fi>
    5  * Copyright (C) 2005,2010 Douglas E. Engert <deengert@gmail.com>
    6  *
    7  * This library is free software; you can redistribute it and/or
    8  * modify it under the terms of the GNU Lesser General Public
    9  * License as published by the Free Software Foundation; either
   10  * version 2.1 of the License, or (at your option) any later version.
   11  *
   12  * This library is distributed in the hope that it will be useful,
   13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   15  * Lesser General Public License for more details.
   16  *
   17  * You should have received a copy of the GNU Lesser General Public
   18  * License along with this library; if not, write to the Free Software
   19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   20  */
   21 
   22 #include "config.h"
   23 
   24 #include <stdio.h>
   25 #include <stdlib.h>
   26 #ifdef HAVE_UNISTD_H
   27 #include <unistd.h>
   28 #endif
   29 #include <string.h>
   30 #include <errno.h>
   31 #include <ctype.h>
   32 #include <sys/stat.h>
   33 
   34 /* Module only built if OPENSSL is enabled */
   35 #include <openssl/opensslv.h>
   36 #include <openssl/opensslconf.h>
   37 #include <openssl/crypto.h>
   38 #include <openssl/conf.h>
   39 
   40 #include <openssl/rsa.h>
   41 #if !defined(OPENSSL_NO_EC) && !defined(OPENSSL_NO_ECDSA)
   42 #include <openssl/ec.h>
   43 #include <openssl/ecdsa.h>
   44 #endif
   45 #include <openssl/evp.h>
   46 #include <openssl/x509.h>
   47 #include <openssl/bn.h>
   48 #include <openssl/bio.h>
   49 #include <openssl/pem.h>
   50 #include <openssl/err.h>
   51 #include <openssl/obj_mac.h>
   52 
   53 #include "libopensc/opensc.h"
   54 #include "libopensc/cardctl.h"
   55 #include "libopensc/cards.h"
   56 #include "libopensc/asn1.h"
   57 #include "util.h"
   58 #include "libopensc/sc-ossl-compat.h"
   59 
   60 static const char *app_name = "piv-tool";
   61 
   62 static int  opt_wait = 0;
   63 static char **  opt_apdus;
   64 static char *   opt_reader;
   65 static int  opt_apdu_count = 0;
   66 static int  verbose = 0;
   67 
   68 enum {
   69     OPT_SERIAL = 0x100,
   70 };
   71 
   72 static const struct option options[] = {
   73     { "serial",     0, NULL,    OPT_SERIAL  },
   74     { "name",       0, NULL,        'n' },
   75     { "admin",      1, NULL,        'A' },
   76     { "genkey",     1, NULL,        'G' },
   77     { "object",     1, NULL,        'O' },
   78     { "cert",       1, NULL,        'C' },
   79     { "compresscert",   1, NULL,        'Z' },
   80     { "out",        1, NULL,        'o' },
   81     { "in",         1, NULL,        'i' },
   82     { "send-apdu",      1, NULL,        's' },
   83     { "reader",     1, NULL,        'r' },
   84     { "wait",       0, NULL,        'w' },
   85     { "verbose",        0, NULL,        'v' },
   86     { NULL, 0, NULL, 0 }
   87 };
   88 
   89 static const char *option_help[] = {
   90     "Print the card serial number",
   91     "Identify the card and print its name",
   92     "Authenticate using default 3DES key",
   93     "Generate key <ref>:<alg> 9A:06 on card, and output pubkey",
   94     "Load an object <containerID> containerID as defined in 800-73 without leading 0x",
   95     "Load a cert <ref> where <ref> is 9A,9C,9D or 9E",
   96     "Load a cert that has been gzipped <ref>",
   97     "Output file for cert or key",
   98     "Input file for cert",
   99     "Sends an APDU in format AA:BB:CC:DD:EE:FF...",
  100     "Uses reader number <arg> [0]",
  101     "Wait for a card to be inserted",
  102     "Verbose operation. Use several times to enable debug output.",
  103 };
  104 
  105 static sc_context_t *ctx = NULL;
  106 static sc_card_t *card = NULL;
  107 static BIO * bp = NULL;
  108 static EVP_PKEY * evpkey = NULL;
  109 
  110 static int load_object(const char * object_id, const char * object_file)
  111 {
  112     FILE *fp = NULL;
  113     sc_path_t path;
  114     size_t derlen;
  115     u8 *der = NULL;
  116     u8 *body;
  117     size_t bodylen;
  118     int r = -1;
  119     struct stat stat_buf;
  120 
  121     if(!object_file || (fp=fopen(object_file, "rb")) == NULL){
  122         printf("Cannot open object file, %s %s\n",
  123             (object_file)?object_file:"", strerror(errno));
  124         goto err;
  125     }
  126 
  127     if (0 != stat(object_file, &stat_buf)) {
  128         printf("unable to read file %s\n",object_file);
  129         goto err;
  130     }
  131     derlen = stat_buf.st_size;
  132     der = malloc(derlen);
  133     if (der == NULL) {
  134         printf("file %s is too big, %lu\n",
  135         object_file, (unsigned long)derlen);
  136         goto err;
  137     }
  138     if (1 != fread(der, derlen, 1, fp)) {
  139         printf("unable to read file %s\n",object_file);
  140         goto err;
  141     }
  142     /* check if tag and length are valid */
  143     body = (u8 *)sc_asn1_find_tag(card->ctx, der, derlen, 0x53, &bodylen);
  144     if (body == NULL || derlen != body  - der +  bodylen) {
  145         fprintf(stderr, "object tag or length not valid\n");
  146         goto err;
  147     }
  148 
  149     sc_format_path(object_id, &path);
  150 
  151     r = sc_select_file(card, &path, NULL);
  152     if (r < 0) {
  153         fprintf(stderr, "select file failed\n");
  154         r = -1;
  155         goto err;
  156     }
  157     /* leave 8 bits for flags, and pass in total length */
  158     r = sc_write_binary(card, 0, der, derlen, derlen<<8);
  159 
  160 err:
  161     free(der);
  162     if (fp)
  163         fclose(fp);
  164 
  165     return r;
  166 }
  167 
  168 
  169 static int load_cert(const char * cert_id, const char * cert_file,
  170                     int compress)
  171 {
  172     X509 * cert = NULL;
  173     FILE *fp = NULL;
  174     u8 buf[1];
  175     size_t buflen = 1;
  176     sc_path_t path;
  177     u8 *der = NULL;
  178     u8 *p;
  179     size_t derlen;
  180     int r = -1;
  181 
  182     if (!cert_file) {
  183         printf("Missing cert file\n");
  184         goto err;
  185     }
  186 
  187     if((fp=fopen(cert_file, "rb"))==NULL){
  188         printf("Cannot open cert file, %s %s\n",
  189                 cert_file, strerror(errno));
  190         goto err;
  191     }
  192     if (compress) { /* file is gzipped already */
  193         struct stat stat_buf;
  194 
  195         if (0 != stat(cert_file, &stat_buf)) {
  196             printf("unable to read file %s\n",cert_file);
  197             goto err;
  198         }
  199         derlen = stat_buf.st_size;
  200         der = malloc(derlen);
  201         if (der == NULL) {
  202             printf("file %s is too big, %lu\n",
  203                 cert_file, (unsigned long)derlen);
  204             goto err;
  205         }
  206         if (1 != fread(der, derlen, 1, fp)) {
  207             printf("unable to read file %s\n",cert_file);
  208             goto err;
  209         }
  210     } else {
  211         cert = PEM_read_X509(fp, &cert, NULL, NULL);
  212         if(cert == NULL){
  213             printf("file %s does not contain PEM-encoded certificate\n",
  214                  cert_file);
  215             goto err;
  216         }
  217 
  218         derlen = i2d_X509(cert, NULL);
  219         der = malloc(derlen);
  220         if (!der) {
  221             goto err;
  222         }
  223         p = der;
  224         i2d_X509(cert, &p);
  225     }
  226     sc_hex_to_bin(cert_id, buf,&buflen);
  227 
  228     switch (buf[0]) {
  229         case 0x9a: sc_format_path("0101",&path); break;
  230         case 0x9c: sc_format_path("0100",&path); break;
  231         case 0x9d: sc_format_path("0102",&path); break;
  232         case 0x9e: sc_format_path("0500",&path); break;
  233         default:
  234             fprintf(stderr,"cert must be 9A, 9C, 9D or 9E\n");
  235             r = 2;
  236             goto err;
  237     }
  238 
  239     r = sc_select_file(card, &path, NULL);
  240     if (r < 0) {
  241         fprintf(stderr, "select file failed\n");
  242         goto err;
  243     }
  244     /* we pass length  and  8 bits of flag to card-piv.c write_binary */
  245     /* pass in its a cert and if needs compress */
  246     r = sc_write_binary(card, 0, der, derlen, (derlen<<8) | (compress<<4) | 1);
  247 
  248 err:
  249     free(der);
  250     if (fp)
  251         fclose(fp);
  252 
  253     return r;
  254 }
  255 static int admin_mode(const char* admin_info)
  256 {
  257     int r;
  258     u8 opts[3];
  259     size_t buflen = 2;
  260 
  261 
  262     if (admin_info && strlen(admin_info) == 7 &&
  263             (admin_info[0] == 'A' || admin_info[0] == 'M') &&
  264             admin_info[1] == ':' &&
  265             (sc_hex_to_bin(admin_info+2, opts+1, &buflen) == 0) &&
  266             buflen == 2) {
  267         opts[0] = admin_info[0];
  268 
  269     } else {
  270         fprintf(stderr, " admin_mode params <M|A>:<keyref>:<alg>\n");
  271         return -1;
  272     }
  273 
  274     r = sc_card_ctl(card, SC_CARDCTL_PIV_AUTHENTICATE, &opts);
  275     if (r)
  276         fprintf(stderr, " admin_mode failed %d\n", r);
  277     return r;
  278 }
  279 
  280 /* generate a new key pair, and save public key in newkey */
  281 static int gen_key(const char * key_info)
  282 {
  283     int r;
  284     u8 buf[2];
  285     size_t buflen = 2;
  286     sc_cardctl_piv_genkey_info_t
  287         keydata = {0, 0, 0, 0, NULL, 0, NULL, 0, NULL, 0};
  288     unsigned long expl;
  289     u8 expc[4];
  290 #if !defined(OPENSSL_NO_EC)
  291     int nid = -1;
  292 #endif
  293     sc_hex_to_bin(key_info, buf, &buflen);
  294     if (buflen != 2) {
  295         fprintf(stderr, "<keyref>:<algid> invalid, example: 9A:06\n");
  296         return 2;
  297     }
  298     switch (buf[0]) {
  299         case 0x9a:
  300         case 0x9c:
  301         case 0x9d:
  302         case 0x9e:
  303             keydata.key_num = buf[0];
  304             break;
  305         default:
  306             fprintf(stderr, "<keyref>:<algid> must be 9A, 9C, 9D or 9E\n");
  307             return 2;
  308     }
  309 
  310     switch (buf[1]) {
  311         case 0x05: keydata.key_bits = 3072; break;
  312         case 0x06: keydata.key_bits = 1024; break;
  313         case 0x07: keydata.key_bits = 2048; break;
  314 #if !defined(OPENSSL_NO_EC)
  315         case 0x11: keydata.key_bits = 0;
  316             nid = NID_X9_62_prime256v1; /* We only support one curve per algid */
  317             break;
  318         case 0x14: keydata.key_bits = 0;
  319             nid = NID_secp384r1;
  320             break;
  321 #endif
  322         default:
  323             fprintf(stderr, "<keyref>:<algid> algid=RSA - 05, 06, 07 for 3072, 1024, 2048;EC - 11, 14 for 256, 384\n");
  324             return 2;
  325     }
  326 
  327     keydata.key_algid = buf[1];
  328 
  329 
  330     r = sc_card_ctl(card, SC_CARDCTL_PIV_GENERATE_KEY, &keydata);
  331     if (r) {
  332         fprintf(stderr, "gen_key failed %d\n", r);
  333         return r;
  334     }
  335 
  336     evpkey = EVP_PKEY_new();
  337 
  338     if (keydata.key_bits > 0) { /* RSA key */
  339         RSA * newkey = NULL;
  340         BIGNUM *newkey_n, *newkey_e;
  341 
  342         newkey = RSA_new();
  343         if (newkey == NULL) {
  344             fprintf(stderr, "gen_key RSA_new failed %d\n",r);
  345             return -1;
  346         }
  347         newkey_n = BN_bin2bn(keydata.pubkey, keydata.pubkey_len, NULL);
  348         expl = keydata.exponent;
  349         expc[3] = (u8) expl & 0xff;
  350         expc[2] = (u8) (expl >>8) & 0xff;
  351         expc[1] = (u8) (expl >>16) & 0xff;
  352         expc[0] = (u8) (expl >>24) & 0xff;
  353         newkey_e =  BN_bin2bn(expc, 4, NULL);
  354 
  355         if (RSA_set0_key(newkey, newkey_n, newkey_e, NULL) != 1) {
  356             fprintf(stderr, "gen_key unable to set RSA values");
  357             return -1;
  358         }
  359 
  360         if (verbose)
  361             RSA_print_fp(stdout, newkey,0);
  362 
  363         EVP_PKEY_assign_RSA(evpkey, newkey);
  364 
  365     } else { /* EC key */
  366 #if !defined(OPENSSL_NO_EC)
  367         int i;
  368         BIGNUM *x;
  369         BIGNUM *y;
  370         EC_KEY * eckey = NULL;
  371         EC_GROUP * ecgroup = NULL;
  372         EC_POINT * ecpoint = NULL;
  373 
  374         ecgroup = EC_GROUP_new_by_curve_name(nid);
  375         EC_GROUP_set_asn1_flag(ecgroup, OPENSSL_EC_NAMED_CURVE);
  376         ecpoint = EC_POINT_new(ecgroup);
  377 
  378         /* PIV returns 04||x||y  and x and y are the same size */
  379         i = (keydata.ecpoint_len - 1)/2;
  380         x = BN_bin2bn(keydata.ecpoint + 1, i, NULL);
  381         y = BN_bin2bn(keydata.ecpoint + 1 + i, i, NULL) ;
  382         r = EC_POINT_set_affine_coordinates_GFp(ecgroup, ecpoint, x, y, NULL);
  383         if (r == 0) {
  384             fprintf(stderr, "EC_POINT_set_affine_coordinates_GFp failed\n");
  385             return -1;
  386         }
  387         eckey = EC_KEY_new();
  388         r = EC_KEY_set_group(eckey, ecgroup);
  389         if (r == 0) {
  390             fprintf(stderr, "EC_KEY_set_group failed\n");
  391             return -1;
  392         }
  393         r = EC_KEY_set_public_key(eckey, ecpoint);
  394         if (r == 0) {
  395             fprintf(stderr, "EC_KEY_set_public_key failed\n");
  396             return -1;
  397         }
  398 
  399         if (verbose)
  400             EC_KEY_print_fp(stdout, eckey, 0);
  401 
  402         EVP_PKEY_assign_EC_KEY(evpkey, eckey);
  403 #else
  404         fprintf(stderr, "This build of OpenSSL does not support EC keys\n");
  405         r = 1;
  406 #endif /* OPENSSL_NO_EC */
  407 
  408     }
  409     if (bp)
  410         r = i2d_PUBKEY_bio(bp, evpkey);
  411 
  412     if (evpkey)
  413         EVP_PKEY_free(evpkey);
  414 
  415     return r;
  416 }
  417 
  418 
  419 static int send_apdu(void)
  420 {
  421     sc_apdu_t apdu;
  422     u8 buf[SC_MAX_APDU_BUFFER_SIZE+3];
  423     u8 rbuf[8192];
  424     size_t len0, r;
  425     int c;
  426 
  427     for (c = 0; c < opt_apdu_count; c++) {
  428         len0 = sizeof(buf);
  429         sc_hex_to_bin(opt_apdus[c], buf, &len0);
  430 
  431         r = sc_bytes2apdu(card->ctx, buf, len0, &apdu);
  432         if (r) {
  433             fprintf(stderr, "Invalid APDU: %s\n", sc_strerror(r));
  434             return 2;
  435         }
  436 
  437         apdu.resp = rbuf;
  438         apdu.resplen = sizeof(rbuf);
  439 
  440         printf("Sending: ");
  441         for (r = 0; r < len0; r++)
  442             printf("%02X ", buf[r]);
  443         printf("\n");
  444         r = sc_transmit_apdu(card, &apdu);
  445         if (r) {
  446             fprintf(stderr, "APDU transmit failed: %s\n", sc_strerror(r));
  447             return 1;
  448         }
  449         printf("Received (SW1=0x%02X, SW2=0x%02X)%s\n", apdu.sw1, apdu.sw2,
  450                apdu.resplen ? ":" : "");
  451         if (apdu.resplen)
  452             util_hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1);
  453     }
  454     return 0;
  455 }
  456 
  457 static void print_serial(sc_card_t *in_card)
  458 {
  459     int r;
  460     sc_serial_number_t serial;
  461 
  462     r = sc_card_ctl(in_card, SC_CARDCTL_GET_SERIALNR, &serial);
  463     if (r < 0)
  464         fprintf(stderr, "sc_card_ctl(*, SC_CARDCTL_GET_SERIALNR, *) failed %d\n", r);
  465     else
  466         util_hex_dump_asc(stdout, serial.value, serial.len, -1);
  467 }
  468 
  469 int main(int argc, char *argv[])
  470 {
  471     int err = 0, r, c;
  472     int do_send_apdu = 0;
  473     int do_admin_mode = 0;
  474     int do_gen_key = 0;
  475     int do_load_cert = 0;
  476     int do_load_object = 0;
  477     int compress_cert = 0;
  478     int do_print_serial = 0;
  479     int do_print_name = 0;
  480     int action_count = 0;
  481     const char *out_file = NULL;
  482     const char *in_file = NULL;
  483     const char *cert_id = NULL;
  484     const char *object_id = NULL;
  485     const char *key_info = NULL;
  486     const char *admin_info = NULL;
  487     sc_context_param_t ctx_param;
  488     char **old_apdus = NULL;
  489 
  490     while ((c = getopt_long(argc, argv, "nA:G:O:Z:C:i:o:r:fvs:c:w", options, (int *) 0)) != -1) {
  491         switch (c) {
  492         case OPT_SERIAL:
  493             do_print_serial = 1;
  494             action_count++;
  495             break;
  496         case 's':
  497             old_apdus = opt_apdus;
  498             opt_apdus = (char **) realloc(opt_apdus,
  499                     (opt_apdu_count + 1) * sizeof(char *));
  500             if (!opt_apdus) {
  501                 free(old_apdus);
  502                 err = 1;
  503                 goto end;
  504             }
  505             opt_apdus[opt_apdu_count] = optarg;
  506             do_send_apdu++;
  507             if (opt_apdu_count == 0)
  508                 action_count++;
  509             opt_apdu_count++;
  510             break;
  511         case 'n':
  512             do_print_name = 1;
  513             action_count++;
  514             break;
  515         case 'A':
  516             do_admin_mode = 1;
  517             admin_info = optarg;
  518             action_count++;
  519             break;
  520         case 'G':
  521             do_gen_key = 1;
  522             key_info = optarg;
  523             action_count++;
  524             break;
  525         case 'O':
  526             do_load_object = 1;
  527             object_id = optarg;
  528             action_count++;
  529             break;
  530         case 'Z':
  531             compress_cert = 1;
  532             /* fall through */
  533         case 'C':
  534             do_load_cert = 1;
  535             cert_id = optarg;
  536             action_count++;
  537             break;
  538         case 'i':
  539             in_file = optarg;
  540             break;
  541         case 'o':
  542             out_file = optarg;
  543             break;
  544         case 'r':
  545             opt_reader = optarg;
  546             break;
  547         case 'v':
  548             verbose++;
  549             break;
  550         case 'w':
  551             opt_wait = 1;
  552             break;
  553         default:
  554             util_print_usage_and_die(app_name, options, option_help, NULL);
  555         }
  556     }
  557 
  558     if (action_count == 0)
  559         util_print_usage_and_die(app_name, options, option_help, NULL);
  560 
  561 
  562 //#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
  563 //  OPENSSL_config(NULL);
  564 //#endif
  565 #if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
  566     OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CRYPTO_STRINGS
  567         | OPENSSL_INIT_ADD_ALL_CIPHERS
  568         | OPENSSL_INIT_ADD_ALL_DIGESTS,
  569         NULL);
  570 #else
  571     /* OpenSSL magic */
  572     OPENSSL_malloc_init();
  573     ERR_load_crypto_strings();
  574     OpenSSL_add_all_algorithms();
  575 
  576 #endif
  577 
  578     if (out_file) {
  579         bp = BIO_new(BIO_s_file());
  580         if (!BIO_write_filename(bp, (char *)out_file))
  581             goto end;
  582     } else {
  583         bp = BIO_new(BIO_s_file());
  584         BIO_set_fp(bp,stdout,BIO_NOCLOSE);
  585     }
  586 
  587     memset(&ctx_param, 0, sizeof(sc_context_param_t));
  588     ctx_param.app_name = app_name;
  589 
  590     r = sc_context_create(&ctx, &ctx_param);
  591     if (r != SC_SUCCESS) {
  592         fprintf(stderr, "Failed to establish context: %s\n", sc_strerror(r));
  593         return 1;
  594     }
  595 
  596     if (action_count <= 0)
  597         goto end;
  598 
  599     /* force PIV card driver */
  600     err = sc_set_card_driver(ctx, "PIV-II");
  601     if (err) {
  602         fprintf(stderr, "PIV card driver not found!\n");
  603         err = 1;
  604         goto end;
  605     }
  606 
  607     err = util_connect_card(ctx, &card, opt_reader, opt_wait, verbose);
  608     if (err)
  609         goto end;
  610 
  611     /* fail if card is not a PIV card */
  612     if (card->type < SC_CARD_TYPE_PIV_II_BASE || card->type >= SC_CARD_TYPE_PIV_II_BASE+1000) {
  613         fprintf(stderr, "Card type %X: not a PIV card\n", card->type);
  614         err = 1;
  615         goto end;
  616     }
  617 
  618     if (do_admin_mode) {
  619         if ((err = admin_mode(admin_info)))
  620             goto end;
  621         action_count--;
  622     }
  623     if (do_send_apdu) {   /* can use pin before load cert for a beta card */
  624         if ((err = send_apdu()))
  625             goto end;
  626         action_count--;
  627     }
  628     if (do_gen_key) {
  629         if ((err = gen_key(key_info)))
  630             goto end;
  631         action_count--;
  632     }
  633     if (do_load_object) {
  634         if ((err = load_object(object_id, in_file)))
  635             goto end;
  636         action_count--;
  637     }
  638     if (do_load_cert) {
  639         if ((err = load_cert(cert_id, in_file, compress_cert)))
  640             goto end;
  641         action_count--;
  642     }
  643     if (do_print_serial) {
  644         if (verbose)
  645             printf("Card serial number:");
  646         print_serial(card);
  647         action_count--;
  648     }
  649     if (do_print_name) {
  650         if (verbose)
  651             printf("Card name: ");
  652         printf("%s\n", card->name);
  653         action_count--;
  654     }
  655 end:
  656     if (bp)
  657         BIO_free(bp);
  658     if (card) {
  659         sc_unlock(card);
  660         sc_disconnect_card(card);
  661     }
  662     sc_release_context(ctx);
  663 
  664     ERR_print_errors_fp(stderr);
  665     return err;
  666 }