Compare commits
5 Commits
0.22.0
...
golem/tess
Author | SHA1 | Date |
---|---|---|
giomba | 932bd27549 | |
giomba | b965e20bfd | |
giomba | 060d8ddb19 | |
giomba | 5167b30043 | |
giomba | 606edadb13 |
|
@ -0,0 +1,3 @@
|
|||
BasedOnStyle: Google
|
||||
IndentWidth: 4
|
||||
|
|
@ -80,6 +80,7 @@ src/tools/pkcs15-init
|
|||
src/tools/eidenv
|
||||
src/tools/opensc-explorer
|
||||
src/tools/cardos-info
|
||||
src/tools/gcns
|
||||
src/tools/sceac-example
|
||||
src/tools/opensc-notify
|
||||
src/tools/opensc-notify.plist
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
/build/
|
|
@ -0,0 +1,12 @@
|
|||
cmake_minimum_required(VERSION 3.18)
|
||||
|
||||
project(gcns VERSION 1.0 DESCRIPTION "Italian healthcare smart card parsing utility")
|
||||
|
||||
add_library(gcns SHARED gcns.c gcns.cpp)
|
||||
target_include_directories(gcns PUBLIC ../.. .. .)
|
||||
install(TARGETS gcns LIBRARY)
|
||||
install(FILES gcns.h gcns.hpp DESTINATION include)
|
||||
|
||||
add_executable(main main.c ../tools/util.c)
|
||||
target_link_libraries(main gcns opensc bsd)
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
# Maintainer: Giovan Battista Rolandi <giomba@linux.it>
|
||||
|
||||
pkgname=gcns
|
||||
pkgver=1.0
|
||||
pkgrel=1
|
||||
pkgdesc='Tools for Italian healthcare smart card'
|
||||
arch=('x86_64')
|
||||
url='https://git.golem.linux.it/giomba/opensc'
|
||||
license=('LGPL')
|
||||
depends=('opensc')
|
||||
source=('git+https://git.golem.linux.it/giomba/opensc#branch=golem/tessera-sanitaria')
|
||||
sha256sums=('SKIP')
|
||||
|
||||
build() {
|
||||
cd opensc
|
||||
|
||||
./bootstrap
|
||||
./configure
|
||||
make -j$(nproc)
|
||||
cd src/gcns
|
||||
|
||||
mkdir -p build
|
||||
cd build
|
||||
cmake ..
|
||||
make -j$(nproc)
|
||||
|
||||
}
|
||||
|
||||
package() {
|
||||
cd opensc/src/gcns/build
|
||||
make DESTDIR=$pkgdir install
|
||||
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* gcns.c: A reader of Italian healtcare smartcards with libopensc
|
||||
*
|
||||
* Copyright (C) 2022 Giovan Battista Rolandi <giomba@linux.it>
|
||||
* based on previous work by
|
||||
* Copyright (C) 2001 Juha Yrjölä <juha.yrjola@iki.fi>
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include "gcns.h"
|
||||
|
||||
#include "libopensc/asn1.h"
|
||||
#include "tools/util.h"
|
||||
|
||||
static int opt_wait = 0;
|
||||
static const char *opt_reader = NULL;
|
||||
static sc_context_t *ctx = NULL;
|
||||
static sc_card_t *card = NULL;
|
||||
sc_context_param_t ctx_param;
|
||||
|
||||
int gcns_init() {
|
||||
int r, err = 0;
|
||||
int lcycle = SC_CARDCTRL_LIFECYCLE_ADMIN;
|
||||
|
||||
memset(&ctx_param, 0, sizeof(ctx_param));
|
||||
ctx_param.ver = 0;
|
||||
|
||||
r = sc_context_create(&ctx, &ctx_param);
|
||||
if (r) {
|
||||
fprintf(stderr, "Failed to establish context: %s\n", sc_strerror(r));
|
||||
return GCNS_INIT;
|
||||
}
|
||||
|
||||
ctx->flags |= SC_CTX_FLAG_ENABLE_DEFAULT_DRIVER;
|
||||
|
||||
err = util_connect_card_ex(ctx, &card, opt_reader, opt_wait, 0, 0);
|
||||
if (err) {
|
||||
return GCNS_INIT;
|
||||
}
|
||||
|
||||
r = sc_lock(card);
|
||||
if (r == SC_SUCCESS)
|
||||
r = sc_card_ctl(card, SC_CARDCTL_LIFECYCLE_SET, &lcycle);
|
||||
sc_unlock(card);
|
||||
if (r && r != SC_ERROR_NOT_SUPPORTED) {
|
||||
fprintf(stderr, "unable to change lifecycle: %s\n", sc_strerror(r));
|
||||
return GCNS_INIT;
|
||||
}
|
||||
|
||||
return GCNS_SUCCESS;
|
||||
}
|
||||
|
||||
int gcns_close() {
|
||||
if (card) {
|
||||
sc_disconnect_card(card);
|
||||
}
|
||||
if (ctx) sc_release_context(ctx);
|
||||
return GCNS_SUCCESS;
|
||||
}
|
||||
|
||||
int gcns_read_personal_data(u8 *buffer, size_t len) {
|
||||
sc_path_t path;
|
||||
int r;
|
||||
|
||||
sc_format_path("3F0011001102", &path);
|
||||
r = sc_select_file(card, &path, NULL);
|
||||
if (r) {
|
||||
fprintf(stderr, "no select file: 3F0011001102\n");
|
||||
return GCNS_READ_PERSONAL_DATA;
|
||||
}
|
||||
r = sc_read_binary(card, 0, buffer, 0x180, 0);
|
||||
if (r < 0) {
|
||||
fprintf(stderr, "no read binary: %d\n", r);
|
||||
return GCNS_READ_PERSONAL_DATA;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
#include "gcns.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
using namespace gcns;
|
||||
|
||||
PersonalData::PersonalData(const uint8_t* buffer, size_t len) {
|
||||
std::vector<std::string> field;
|
||||
|
||||
// TODO check length at the beginning?
|
||||
for (int i = 12; i < len;) {
|
||||
if (buffer[i] == '\0') break;
|
||||
|
||||
std::string hexstring((const char*)&buffer[i], 2);
|
||||
int len = std::stoi(hexstring, nullptr, 16);
|
||||
i += 2;
|
||||
std::string fieldData((const char*)&buffer[i], len);
|
||||
i += len;
|
||||
|
||||
field.push_back(fieldData);
|
||||
}
|
||||
|
||||
for (int i = 0; i < (int)field.size(); ++i) {
|
||||
switch (i) {
|
||||
case 0:
|
||||
this->issue_date.year =
|
||||
std::stoi(field[i].substr(4, 4), nullptr);
|
||||
this->issue_date.month =
|
||||
std::stoi(field[i].substr(2, 2), nullptr);
|
||||
this->issue_date.day =
|
||||
std::stoi(field[i].substr(0, 2), nullptr);
|
||||
break;
|
||||
case 1:
|
||||
this->expiration_date.year =
|
||||
std::stoi(field[i].substr(4, 4), nullptr);
|
||||
this->expiration_date.month =
|
||||
std::stoi(field[i].substr(2, 2), nullptr);
|
||||
this->expiration_date.day =
|
||||
std::stoi(field[i].substr(0, 2), nullptr);
|
||||
break;
|
||||
case 2:
|
||||
this->family_name = field[i];
|
||||
break;
|
||||
case 3:
|
||||
this->first_name = field[i];
|
||||
break;
|
||||
case 4:
|
||||
this->birth_date.year =
|
||||
std::stoi(field[i].substr(4, 4), nullptr);
|
||||
this->birth_date.month =
|
||||
std::stoi(field[i].substr(2, 2), nullptr);
|
||||
this->birth_date.day =
|
||||
std::stoi(field[i].substr(0, 2), nullptr);
|
||||
break;
|
||||
case 5:
|
||||
this->gender = field[i] == "F" ? GENDER_FEMALE : GENDER_MALE;
|
||||
break;
|
||||
case 7:
|
||||
this->fiscal_code = field[i];
|
||||
break;
|
||||
case 9:
|
||||
this->birth_place = field[i];
|
||||
break;
|
||||
case 12:
|
||||
this->residence_place = field[i];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
#ifndef GCNS_H
|
||||
#define GCNS_H
|
||||
|
||||
#define GCNS_SUCCESS 0
|
||||
#define GCNS_INIT -1001
|
||||
#define GCNS_READ_PERSONAL_DATA -1002
|
||||
#define GCNS_CLOSE -1003
|
||||
|
||||
int gcns_init();
|
||||
int gcns_read_personal_data(u8 *buffer, size_t len);
|
||||
int gcns_close();
|
||||
|
||||
#endif
|
|
@ -0,0 +1,34 @@
|
|||
#ifndef GCNS_CPP
|
||||
#define GCNS_CPP
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace gcns {
|
||||
|
||||
enum Gender { GENDER_MALE, GENDER_FEMALE };
|
||||
|
||||
struct Date {
|
||||
uint16_t year;
|
||||
uint8_t month;
|
||||
uint8_t day;
|
||||
};
|
||||
|
||||
class PersonalData {
|
||||
private:
|
||||
std::string first_name;
|
||||
std::string family_name;
|
||||
std::string fiscal_code;
|
||||
std::string birth_place;
|
||||
Date birth_date;
|
||||
std::string residence_place;
|
||||
Gender gender;
|
||||
Date issue_date;
|
||||
Date expiration_date;
|
||||
|
||||
public:
|
||||
PersonalData(const uint8_t* personal_data, size_t len);
|
||||
};
|
||||
|
||||
} // namespace gcns
|
||||
|
||||
#endif
|
|
@ -0,0 +1,56 @@
|
|||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "config.h"
|
||||
#ifdef ENABLE_READLINE
|
||||
#include <readline/history.h>
|
||||
#include <readline/readline.h>
|
||||
#endif
|
||||
#if !defined(_WIN32)
|
||||
#include <arpa/inet.h> /* for htons() */
|
||||
#endif
|
||||
|
||||
#include <getopt.h>
|
||||
|
||||
#include "common/compat_strlcpy.h"
|
||||
#include "gcns.h"
|
||||
#include "libopensc/asn1.h"
|
||||
#include "libopensc/cardctl.h"
|
||||
#include "libopensc/cards.h"
|
||||
#include "libopensc/internal.h"
|
||||
#include "libopensc/iso7816.h"
|
||||
#include "libopensc/log.h"
|
||||
#include "libopensc/opensc.h"
|
||||
#include "tools/util.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int r;
|
||||
|
||||
printf("OpenSC version: %s\n", sc_get_version());
|
||||
|
||||
r = gcns_init();
|
||||
if (r != GCNS_SUCCESS) {
|
||||
fprintf(stderr, "Init Error\n");
|
||||
return GCNS_INIT;
|
||||
}
|
||||
|
||||
u8 buffer[2048];
|
||||
r = gcns_read_personal_data(buffer, 2048);
|
||||
|
||||
if (r < 0) {
|
||||
fprintf(stderr, "Read personal data error\n");
|
||||
return GCNS_READ_PERSONAL_DATA;
|
||||
}
|
||||
|
||||
util_hex_dump_asc(stdout, buffer, r, 0);
|
||||
|
||||
r = gcns_close();
|
||||
if (r != GCNS_SUCCESS) {
|
||||
return GCNS_CLOSE;
|
||||
}
|
||||
|
||||
return GCNS_SUCCESS;
|
||||
}
|
Loading…
Reference in New Issue