From a6db0256c9194201f658b389e0f32ebe3f7f5cde Mon Sep 17 00:00:00 2001 From: nils Date: Tue, 14 Jun 2005 21:37:19 +0000 Subject: [PATCH] add netkey-tool from Peter Koch git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@2349 c6295689-39f2-0310-b995-f0e70906c6a9 --- docs/Makefile.am | 1 + docs/netkey-tool.1 | 102 +++++++ src/tools/Makefile.am | 4 +- src/tools/netkey-tool.c | 637 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 743 insertions(+), 1 deletion(-) create mode 100644 docs/netkey-tool.1 create mode 100644 src/tools/netkey-tool.c diff --git a/docs/Makefile.am b/docs/Makefile.am index bea78551..0d9252b4 100644 --- a/docs/Makefile.am +++ b/docs/Makefile.am @@ -16,6 +16,7 @@ MANSRC = \ pkcs15-tool.1 \ pkcs11-tool.1 \ cardos-info.1 \ + netkey-tool.1 \ opensc.7 \ pkcs15.7 \ sc_connect_card.3 \ diff --git a/docs/netkey-tool.1 b/docs/netkey-tool.1 new file mode 100644 index 00000000..a43ad3fb --- /dev/null +++ b/docs/netkey-tool.1 @@ -0,0 +1,102 @@ +.PU +.ds nm \fBnetkey-tool\fR +.TH netkey-tool 1 "May 16, 2005" "" OpenSC +.SH NAME +netkey-tool \- utility for NetKey E4 smartcards +.SH SYNOPSIS +\*(nm +.RI [OPTIONS] +[command] +.SH DESCRIPTION +The \*(nm utility can be used from the command line to perform +some smart card operations with NetKey E4 cards that cannot +be done easily with other OpenSC-tools, such as changing local +PINs, storing certificates into empty NetKey E4 cert-files or +displaying the initial PUK-value. +.SH OPTIONS +.TP +.BR \-\-help ", " \-h +Displays a short help message. +format +.TP +.BR \-v +Causes \*(nm to be more verbose. Specify this flag several times +to enable debug output in the opensc library. +.TP +.BR "\-\-pin " \fIpin-value\fP ", \-p " \fIpin-value\fP +Specifies the current value of the global PIN. +.TP +.BR "\-\-puk " \fIpin-value\fP ", \-u " \fIpin-value\fP +Specifies the current value of the global PUK. +.TP +.BR "\-\-pin0 " \fIpin-value\fP ", \-0 " \fIpin-value\fP +Specifies the current value of the local PIN0 (aka local PIN). +.TP +.BR "\-\-pin1 " \fIpin-value\fP ", \-1 " \fIpin-value\fP +Specifies the current value of the local PIN1 (aka local PUK). +.SH PIN FORMAT +With \fIpin-value\fP you can specify one of the cards pins. +You may use plain ascii-strings (i.e. 123456) or a hex-string +(i.e. 31:32:33:34:35:36). A hex-string consists +of exacly n 2-digit hexnumbers separated by n-1 colons. +Don't use leading or trailing colons or 1-digit hex-numbers. :12:34: +and 1:2:3:4 are both pins of length 7 and you most likely +intedend to use 12:34 or 01:02:03:04 wich are pins of length +2 and 4. +.SH COMMANDS +When used without any options or commands, \*(nm will +display information about the smartcards pins and +certificates. This will not change your card in +any aspect (assumed there are no bugs in \*(nm). +In particular the tries-left counters of the pins +are investigated without doing actual pin-verifications. + +If you specify the global PIN via the \fB\-\-pin\fP option, +\*(nm will also display the initial value of the cards +global PUK. If your global PUK was changed \*(nm will +still diplay its initial value. There's no way to recover +a lost global PUK once it was changed and got lost. There's +also no way to display the initial value of your global +PUK without knowing the current value of your global PIN. + +For most of the commands that \*(nm can execute, you have +to specify one pin. One notable exeption is the +\fBnullpin\fP command, but this command can only be executed +once in the lifetime of a NetKey E4 card. +.IP "\fBunblock pin | pin0 | pin1\fP" 4 +This unblocks the specified pin. This needs the value +of another pin and if you don't specify a correct one, +\*(nm will tell you which one is needed. +.IP "\fBchange pin | puk | pin0 | pin1 \fIpin-value\fP" 4 +This changes the value of the specified pin to the given +new value. This needs the value of either the same +pin or another pin and if you don't specify a correct one, +\*(nm will tell you which one is needed. +.IP "\fBnullpin \fIpin-value\fP" 4 +This command can be executed only if the global PIN +of your card is in nullpin-state. There's no way to +return back to nullpin-state once you have changed +your global PIN. You don't need a pin to execute +the nullpin-command. After a succesfull nullpin-command +\*(nm will display your cards initial PUK-value. +.IP "\fBcert \fIno\fP \fIfilename\fP" 4 +This command will read one of your cards certificates +(as specified by number \fIno\fP) and save this +certificate into file \fIfilename\fP in PEM-format. +Certificates on a NetKey E4 card are readable without +a pin, so you don't have to specify one. +.IP "\fBcert \fIfilename\fP \fIno\fP" 4 +This command will read the first PEM-encoded certificate from +file \fIfilename\fP and store this into your smartcards +certificate file number \fIno\fP. Some of your +smartcards certificate files might be readonly, so +this will not work with all values of \fIno\fP. If +a certificate file is writable you must specify a +pin in order to change it. If you try to use this +command without specifying a pin, \*(nm will tell +you which one is needed. +.SH SEE ALSO +.BR opensc (7), +.BR opensc-explorer (1) +.SH AUTHORS +\*(nm was written by Peter Koch . diff --git a/src/tools/Makefile.am b/src/tools/Makefile.am index 15cce5ed..e0bb931c 100644 --- a/src/tools/Makefile.am +++ b/src/tools/Makefile.am @@ -7,7 +7,7 @@ EXTRA_DIST = Makefile.mak AM_LDFLAGS = @LIBOPENSC@ if HAVE_SSL -PROGRAMS_SSL = cryptoflex-tool pkcs15-init +PROGRAMS_SSL = cryptoflex-tool pkcs15-init netkey-tool endif bin_PROGRAMS = opensc-tool opensc-explorer pkcs15-tool pkcs15-crypt \ @@ -32,5 +32,7 @@ cardos_info_SOURCES = cardos-info.c util.c cardos_info_LDADD = @GETOPTSRC@ eidenv_SOURCES = eidenv.c eidenv_LDADD = @GETOPTSRC@ +netkey_tool_SOURCES = netkey-tool.c +netkey_tool_LDADD = @GETOPTSRC@ @LIBCRYPTO@ noinst_HEADERS = util.h diff --git a/src/tools/netkey-tool.c b/src/tools/netkey-tool.c new file mode 100644 index 00000000..277aacc7 --- /dev/null +++ b/src/tools/netkey-tool.c @@ -0,0 +1,637 @@ +/* + * Netkey-Tool for Telesec Netkey E4 cards. + * + * compile with: + * gcc -I/include -I/include \ + * -L/lib -L/lib \ + * -o netkey-tool netkey-tool.c -lopensc -lcrypto + * + * Copyright (C) 2005, Peter Koch + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef HAVE_CONFIG_H +# include +#else +# ifdef linux +# define HAVE_GETOPT_H +# endif +#endif + +#include +#include +#ifdef HAVE_GETOPT_H +# include +#endif +#include +#include +#include +#include +#include + +static struct { + char *path; + int readonly; + char *label; +} certlist[]={ + {"DF01C000", 1, "Telesec Signatur Zertifikat"}, + {"DF014331", 0, "User Signatur Zertifikat1"}, + {"DF014332", 0, "User Signatur Zertifikat2"}, + {"DF01C100", 1, "Telesec Authentifizierungs Zertifikat"}, + {"DF014371", 0, "User Authentifizierungs Zertifikat1"}, + {"DF014372", 0, "User Authentifizierungs Zertifikat2"}, + {"DF01C200", 1, "Telesec Verschlüsselungs Zertifikat"}, + {"DF0143B1", 0, "User Verschlüsselungs Zertifikat1"}, + {"DF0143B2", 0, "User Verschlüsselungs Zertifikat2"}, +}; + +static struct { + char *path; + char *name; + char *label; + int p1, p2; + int tries; + int len; + u8 value[32]; +} pinlist[]={ + {"3F005000", "pin", "global PIN", 1,-1, 0, 0}, + {"3F005001", "puk", "global PUK", -1,-1, 0, 0}, + {"3F00DF015080", "pin0", "local PIN0", 3, 0, 0, 0}, + {"3F00DF015081", "pin1", "local PIN1", 0,-1, 0, 0}, +}; + + +void show_pin( + sc_card_t *card, + int pin +){ + sc_path_t p; + sc_file_t *f; + struct sc_apdu a; + int i, max; + + sc_format_path(pinlist[pin].path,&p); + if((i=sc_select_file(card,&p,&f))<0){ + printf("\nCannot select PIN-file %s, is this a NetKey-Card ??\n", pinlist[pin].path); + return; + } + if(f->type!=SC_FILE_TYPE_WORKING_EF || f->ef_structure!=SC_FILE_EF_LINEAR_VARIABLE_TLV || + f->prop_attr_len!=5 || f->prop_attr[0]!=0x01 || f->prop_attr[1]!=0x80 + ){ + printf("\nInvald PIN-file: Type=%d, EF-Structure=%d, Prop-Len=%d %02X:%02X:%02X\n", + f->type, f->ef_structure, f->prop_attr_len, + f->prop_attr[0], f->prop_attr[1], f->prop_attr[2] + ); + return; + } + pinlist[pin].tries=f->prop_attr[3], max=f->prop_attr[4]; + + if(pinlist[pin].len){ + sc_format_apdu(card, &a, SC_APDU_CASE_3_SHORT, 0x20, 0x00, f->prop_attr[2] | (pin>1 ? 0x80 : 0x00) ); + a.data=pinlist[pin].value, a.lc=a.datalen=pinlist[pin].len; + } else { + sc_format_apdu(card, &a, SC_APDU_CASE_1, 0x20, 0x00, f->prop_attr[2] | (pin>1 ? 0x80 : 0x00) ); + } + if((i=sc_transmit_apdu(card, &a))<0){ + printf("\nsc_transmit_apdu() failed, %s\n", sc_strerror(i)); + return; + } + printf("%s: %d tries left, %d tries max, ", pinlist[pin].label, pinlist[pin].tries, max); + if(a.sw1==0x63 && (a.sw2&0xF0)==0xC0) printf("not verified\n"); + else if(a.sw1==0x90 && a.sw2==0x00) printf("verified\n"); + else if(a.sw1==0x69 && a.sw2==0x83) printf("blocked\n"); + else if(a.sw1==0x69 && a.sw2==0x85) printf("NullPin\n"); + else printf("Error %02X%02X\n", a.sw1, a.sw2); +} + +void show_certs( + sc_card_t *card +){ + sc_path_t p; + sc_file_t *f; + X509 *c; + u8 buf[2000], *q; + int i, j; + + printf("\n"); + for(i=0;itype!=SC_FILE_TYPE_WORKING_EF || f->ef_structure!=SC_FILE_EF_TRANSPARENT){ + printf(", Invald Cert-file: Type=%d, EF-Structure=%d\n", f->type, f->ef_structure); + continue; + } + if((j=sc_read_binary(card,0,buf,f->size,0))<0){ + printf(", Cannot read Cert-file, %s\n", sc_strerror(j)); + continue; + } + printf(", Maxlen=%u", f->size); + q=buf; + if(q[0]==0x30 && q[1]==0x82){ + if(q[4]==6 && q[5]<10 && q[q[5]+6]==0x30 && q[q[5]+7]==0x82) q+=q[5]+6; + printf(", Len=%u\n", (q[2]<<8)|q[3]); + if((c=d2i_X509(NULL,&q,f->size))){ + X509_NAME_get_text_by_NID(c->cert_info->subject, NID_commonName, buf,sizeof(buf)); + printf(" Subject-CN: %s\n", buf); + X509_NAME_get_text_by_NID(c->cert_info->issuer, NID_commonName, buf,sizeof(buf)); + printf(" Issuer-CN: %s\n", buf); + X509_free(c); + } else printf(" Invalid Certificate-Data\n"); + } else printf(", empty\n"); + } +} + +void show_initial_puk( + sc_card_t *card +){ + sc_path_t p; + sc_file_t *f; + struct sc_apdu a; + u8 buf1[128], buf2[128]; + int i; + + printf("\nReading crypted Initial-PUK-file: "); + sc_format_path("3F004350",&p); + if((i=sc_select_file(card,&p,&f))<0){ + printf("Cannot select crypted Initial-PUK-file, %s\n", sc_strerror(i)); + return; + } + if((i=sc_read_binary(card,0,buf1,128,0))!=128){ + printf("Cannot read crypted Initial-PUK-file, %s\n", sc_strerror(i)); + return; + } + + printf("OK\nDecrypting crypted Initial-PUK-file: "); + sc_format_path("3F00DF01",&p); + if((i=sc_select_file(card,&p,&f))<0){ + printf("Cannot select DF01, %s\n", sc_strerror(i)); + return; + } + sc_format_apdu(card, &a, SC_APDU_CASE_3_SHORT, 0x22, 0xC1, 0xB8); + buf2[0]=0x80, buf2[1]=0x01, buf2[2]=0x10, buf2[3]=0x84, buf2[4]=0x01, buf2[5]=0x81; + a.data=buf2, a.lc=a.datalen=6; + if((i=sc_transmit_apdu(card, &a))<0){ + printf("sc_transmit_apdu(MSE) failed, %s\n", sc_strerror(i)); + return; + } + if(a.sw1!=0x90 && a.sw2!=0x00){ + printf("MSE=%02X%02X\n", a.sw1, a.sw2); + return; + } + sc_format_apdu(card, &a, SC_APDU_CASE_4_SHORT, 0x2A, 0x84, 0x80); + a.data=buf1, a.lc=a.datalen=128; + a.resp=buf2, a.le=a.resplen=128; + if((i=sc_transmit_apdu(card, &a))<0){ + printf("sc_transmit_apdu(PSO) failed, %s\n", sc_strerror(i)); + return; + } + if(a.sw1!=0x90 && a.sw2!=0x00){ + printf("PSO=%02X%02X\n", a.sw1, a.sw2); + return; + } + printf("OK ==> Initial-PUK:"); for(i=120;i<128;++i) printf("%c",buf2[i]); printf("\n"); +} + +void show_card( + sc_card_t *card +){ + sc_path_t path; + sc_file_t *file; + u8 buf[100]; + int i, len; + + sc_format_path("3F002F02",&path); + if((i=sc_select_file(card,&path,&file))<0){ + printf("\nCannot select Serial-Number 2F02, is this a NetKey-Card ??\n"); + return; + } + if(file->type!=SC_FILE_TYPE_WORKING_EF || file->ef_structure!=SC_FILE_EF_TRANSPARENT || + file->size!=12 || (len=sc_read_binary(card,0,buf,12,0))!=12 || buf[0]!=0x5A || buf[1]!=0x0A + ){ + printf("\nInvald Serial-Number: Type=%d, EF-Structure=%d, Size=%d\n", + file->type, file->ef_structure, file->size + ); + return; + } + printf("\nSerial-Number: "); + for(i=2;i<11;++i) printf("%02X", buf[i]); + printf("%X\n\n", buf[11]>>4); + + for(i=0;i<4;++i) show_pin(card, i); + // printf("%s: %u tries left, %u tries max, %s\n", pinlist[i].label, pinlist[i].tries, max, status); + + if(pinlist[0].len) show_initial_puk(card); +} + + +void handle_change( + sc_card_t *card, + int pin1, + int pin2, + int do_change, + u8 *newpin, + int newlen +){ + sc_path_t p; + sc_file_t *f; + struct sc_apdu a; + u8 ref; + int i; + + printf("\n%s %s with %s: ", do_change ? "Changing" : "Unblocking", pinlist[pin1].label, pinlist[pin2].label); + + sc_format_path(pinlist[pin1].path,&p); + if((i=sc_select_file(card,&p,&f))<0){ + printf("\nCannot select %s, %s\n", pinlist[pin1].label, sc_strerror(i)); + return; + } + ref=f->prop_attr[2] | (strlen(pinlist[pin1].path)>8 ? 0x80 : 0x00); + + if(do_change){ + sc_format_apdu(card, &a, SC_APDU_CASE_3_SHORT, 0x24, 0x01, ref); + a.data=newpin, a.lc=a.datalen=newlen; + } else { + sc_format_apdu(card, &a, SC_APDU_CASE_1, 0x2C, 0x03, ref); + } + if((i=sc_transmit_apdu(card, &a))<0){ + printf("\nsc_transmit_apdu() failed, %s\n", sc_strerror(i)); + return; + } + if(a.sw1!=0x90 && a.sw2!=0x00){ + printf("%02X%02X\n", a.sw1, a.sw2); + return; + } + printf("OK\n"); +} + + +void handle_nullpin( + sc_card_t *card, + u8 *newpin, + int newlen +){ + sc_path_t p; + sc_file_t *f; + struct sc_apdu a; + u8 ref, buf[40]; + int i; + + printf("\nSetting initial PIN-value: "); + + sc_format_path(pinlist[0].path,&p); + if((i=sc_select_file(card,&p,&f))<0){ + printf("\nCannot select %s, %s\n", pinlist[0].label, sc_strerror(i)); + return; + } + ref=f->prop_attr[2]; + + sc_format_apdu(card, &a, SC_APDU_CASE_1, 0x20, 0x00, f->prop_attr[2]); + if((i=sc_transmit_apdu(card, &a))<0){ + printf("sc_transmit_apdu() failed, %s\n", sc_strerror(i)); + return; + } + if(a.sw1!=0x69 && a.sw2!=0x85){ + printf("global PIN is not in NullPin-state (%02X%02X)\n", a.sw1, a.sw2); + return; + } + + sc_format_apdu(card, &a, SC_APDU_CASE_3_SHORT, 0x24, 0x00, ref); + for(i=0;i<6;++i) buf[i]=0; + for(i=0;isize,0))<0){ + printf("Cannot read Cert, %s\n", sc_strerror(len)); + return; + } + q=buf; + if(q[0]==0x30 && q[1]==0x82 && q[4]==6 && q[5]<10 && q[q[5]+6]==0x30 && q[q[5]+7]==0x82) q+=q[5]+6; + if((c=d2i_X509(NULL,&q,len))==NULL){ + printf("cardfile contains %d bytes which are not a certificate\n", len); + return; + } + printf("Writing Cert to %s: ", file); fflush(stdout); + if((fp=fopen(file,"w"))==NULL) printf("Cannot open file, %s\n", strerror(errno)); + else { + fprintf(fp,"Certificate %d from Netkey E4 card\n\n", cert); + PEM_write_X509(fp,c); + printf("OK\n"); + } + X509_free(c); +} + + +void handle_writecert( + sc_card_t *card, + int cert, + char *file +){ + sc_path_t p; + sc_file_t *f; + FILE *fp; + X509 *c; + u8 buf[1536], *q; + int i, len; + + printf("\nReading Cert from %s: ", file); fflush(stdout); + + if((fp=fopen(file,"r"))==NULL){ + printf("Cannot open file, %s\n", strerror(errno)); + return; + } + c=PEM_read_X509(fp,NULL,NULL,NULL); + fclose(fp); + if(c==NULL){ + printf("file does not conatin PEM-encoded certificate\n"); + return; + } + printf("OK\nStoring Cert into Card-Certificate %d: ", cert); fflush(stdout); + q=buf; len=i2d_X509(c,NULL); if(len>0 && len<=sizeof(buf)) i2d_X509(c,&q); + X509_free(c); + if(len<=0 || len>sizeof(buf)){ + printf("certificate too long or invalid (Len=%d)\n", len); + return; + } + + sc_format_path(certlist[cert].path,&p); + if((i=sc_select_file(card,&p,&f))<0){ + printf("cannot select certfile, %s\n", sc_strerror(i)); + return; + } + if((i=sc_update_binary(card,0,buf,len,0))<0){ + printf("cannot store cert, %s\n", sc_strerror(i)); + return; + } + printf("OK\n"); +} + + +int pin_string2int( + char *s +){ + int i; + + for(i=0;i=5 && len%3==2); + if(hex){ + len=(len+1)/3; + hex=(len<=32); + } + for(i=0;hex && i0 && pin[3*i-1]!=':') hex=0; + else j=strtol(pin+3*i,&p,16); + if(hex && (j<0 || j>255 || (p-pin)!=3*i+2)) hex=0; + } + if(hex){ + for(i=0;hex && i32) len=32; + for(i=0;i\n"); + fprintf(stderr,"usage: %s command\n", argv[0]); + fprintf(stderr,"\nOptions:\n"); + fprintf(stderr," -v : verbose, may be specified several times\n"); + fprintf(stderr," --reader , -r : use reader num (default 0)\n"); + fprintf(stderr," --pin , -p : global PIN\n"); + fprintf(stderr," --puk , -u : global PUK\n"); + fprintf(stderr," --pin0 , -0 : local PIN0\n"); + fprintf(stderr," --pin1 , -1 : local PIN1\n"); + fprintf(stderr,"\nCommands:\n"); + fprintf(stderr," unblock {pin | pin0 | pin1}\n"); + fprintf(stderr," change {pin | puk | pin0 | pin1} \n"); + fprintf(stderr," nullpin \n"); + fprintf(stderr," cert \n"); + fprintf(stderr," cert \n"); + fprintf(stderr,"\nExamples:\n"); + fprintf(stderr,"list PINs and Certs without changing anything. Try this first!!\n"); + fprintf(stderr," %s\n", argv[0]); + fprintf(stderr,"\nlist PINs and Certs and initial PUK-value (after verification of global PIN)\n"); + fprintf(stderr," %s --pin 123456\n", argv[0]); + fprintf(stderr,"\nchange local PIN0 to 654321 after verification of global PIN\n"); + fprintf(stderr," %s --pin 123456 change pin0 654321\n", argv[0]); + fprintf(stderr,"\nchange global PIN from hex 01:02:03:04:05:06 to ascii 123456\n"); + fprintf(stderr," %s --pin 01:02:03:04:05:06 change pin 123456\n", argv[0]); + fprintf(stderr,"\nunblock global PIN with global PUK\n"); + fprintf(stderr," %s --puk 12345678 unblock pin\n", argv[0]); + fprintf(stderr,"\nset global PIN to initial value when in NullPin-state\n"); + fprintf(stderr," %s nullpin 123456\n", argv[0]); + fprintf(stderr,"\nstore Certificate into card at position 2 and read it back into file\n"); + fprintf(stderr," %s --pin1 123456 cert /tmp/cert1 2\n", argv[0]); + fprintf(stderr," %s cert 2 /tmp/cert2\n", argv[0]); + fprintf(stderr,"\nBe carful - this tool may destroy your card\n"); + fprintf(stderr,"\nQuestions? Comments? ==> opensc-user@opensc.org\n"); + exit(1); + } + if(optind==argc-2 && !strcmp(argv[optind],"unblock")){ + ++optind, do_unblock=1; + pin_nr=pin_string2int(argv[optind++]); + if(pin_nr<0 || pin_nr==1) ++oerr; + } + if(optind==argc-3 && !strcmp(argv[optind],"change")){ + ++optind, do_change=1; + pin_nr=pin_string2int(argv[optind++]); + if(pin_nr<0 || pin_nr>3) ++oerr; + set_pin(newpin,&newlen,argv[optind++]); + } + if(optind==argc-2 && !strcmp(argv[optind],"nullpin")){ + ++optind, do_nullpin=1; + set_pin(newpin,&newlen,argv[optind++]); + } + if(optind==argc-3 && !strcmp(argv[optind],"cert")){ + ++optind; + cert_nr=strtol(argv[optind],&p,10); + if(argv[optind][0] && !*p && cert_nr>=0 && cert_nr=sizeof(certlist)/sizeof(certlist[0])) ++oerr; + } + optind+=2; + } + if(oerr || optind!=argc){ + fprintf(stderr,"%s: invalid usage, try --help\n", argv[0]); + exit(1); + } + + if((i=sc_establish_context(&ctx, argv[0]))<0){ + fprintf(stderr,"Establish-Context failed: %s\n", sc_strerror(i)); + exit(1); + } + ctx->debug=debug; + if(ctx->debug>0) printf("Context for application \"%s\" created, Debug=%d\n", ctx->app_name, ctx->debug); + + for(i=0;ctx->card_drivers[i];++i) if(!strcmp("tcos", ctx->card_drivers[i]->short_name)) break; + if(!ctx->card_drivers[i]){ + fprintf(stderr,"Context does not support TCOS-cards\n"); + exit(1); + } + + printf("%d Reader detected\n", ctx->reader_count); + for(i=0;ireader_count;++i){ + printf("%d: %s, Driver: %s, %d Slot(s)\n", + i, ctx->reader[i]->name, ctx->reader[i]->driver->name, + ctx->reader[i]->slot_count + ); + } + if(reader<0 || reader>=ctx->reader_count){ + fprintf(stderr,"Cannot open reader %d\n", reader); + exit(1); + } + + if((i=sc_connect_card(ctx->reader[0], 0, &card))<0){ + fprintf(stderr,"Connect-Card failed: %s\n", sc_strerror(i)); + exit(1); + } + printf("\nCard detected (driver: %s)\nATR:", card->driver->name); + for(i=0;iatr_len;++i) printf("%c%02X", i?':':' ', card->atr[i]); printf("\n"); + + if((i=sc_lock(card))<0){ + fprintf(stderr,"Lock failed: %s\n", sc_strerror(i)); + exit(1); + } + + show_card(card); + + if(do_unblock || do_change){ + int i1=pinlist[pin_nr].p1, i2=pinlist[pin_nr].p2; + + if((do_unblock || !pinlist[pin_nr].len) && + (i1<0 || !pinlist[i1].len) && (i2<0 || !pinlist[i2].len) + ){ + fprintf(stderr, "\nNeed %s", do_change ? pinlist[pin_nr].label : pinlist[i1].label); + if(do_change && i1>=0) fprintf(stderr, " or %s", pinlist[i1].label); + if(i2>=0) fprintf(stderr, " or %s", pinlist[i2].label); + fprintf(stderr, " to %s %s\n", do_change ? "change" : "unblock", pinlist[pin_nr].label); + } else { + if(do_change && pinlist[pin_nr].len) i1=pin_nr; + if(i1<0 || !pinlist[i1].len) i1=i2; + handle_change(card, pin_nr, i1, do_change, newpin, newlen); + } + } + + if(do_nullpin){ + handle_nullpin(card, newpin, newlen); + show_initial_puk(card); + } + + if(do_readcert) handle_readcert(card, cert_nr, certfile); + if(do_writecert){ + if(certlist[cert_nr].readonly){ + fprintf(stderr, "\nReadonly-Certificate %d cannot be changed\n", cert_nr); + } else if(!pinlist[0].len && !pinlist[3].len){ + fprintf(stderr, "\nNeed %s or %s to change Card-Certificate %d\n", + pinlist[0].label, pinlist[3].label, cert_nr + ); + } else handle_writecert(card, cert_nr, certfile); + } + + if(do_unblock+do_change+do_nullpin+do_readcert==0) show_certs(card); + + sc_unlock(card); + sc_disconnect_card(card,0); + sc_release_context(ctx); + + exit(0); +}