Giter VIP home page Giter VIP logo

esteid.js's Introduction

esteid.js · npm version

Provides a high level API that transaltes to low level APDU interface of EstEID cards, in JavaScript.

For NodeJS and browsers.

BIBO transmit explained

Requires the availability of a reliable Promise based BIBO (Bytes-go-In, Bytes-come-Out) transmit function. That is, a function that takes an APDU and returns a Promise that would resolve to the response from the card, that with a mix of PC/SC and JavaScript would look something like:

function transmit(Buffer apdu) {
   return new Promise((resolve, reject) => resolve(SCardTransmit(apdu)))
}

Three implementations are provided:

Development

You need a recent NodeJS and developer tools for native code compilation. On Windows also OpenSSL 1.0.X that matches the architecture of NodeJS.

git clone https://github.com/martinpaljak/esteid.js
cd esteid.js
npm install
npm test

Give the target you want to test as parameter to npm test

API and usage

First

npm install --save-dev esteid

then

const esteid = require('esteid')

esteid.connect(transmit)

Creates an instance of EstEID, bound to the transmit channel. Takes the BIBO-Promise-function as the parameter.

var EstEID = esteid.connect(transmit)

EstEID.getPersonalData(fields)

Returns a Promise that resolves to the personal data file contents. Takes a field name (string) or a list of field names as a parameter. By default reads all fields.

EstEID.getPersonalData().then(
  (data) => console.log(JSON.stringify(data, null, 2))
)

Would show

{
  "SURNAME": "PALJAK",
  "GIVEN_NAMES1": "MARTIN",
  "GIVEN_NAMES2": "",
  "SEX": "M",
  "CITIZENSHIP": "EST",
  "DATE_OF_BIRTH": "16.07.1982",
  "PERSONAL_ID": "38207162722",
  "DOCUMENT_NR": "AA044XXXX",
  "EXPIRY_DATE": "23.11.2017",
  "PLACE_OF_BIRTH": "EESTI / EST",
  "ISSUING_DATE": "08.05.2013",
  "PERMIT_TYPE": "",
  "REMARK1": "",
  "REMARK2": "",
  "REMARK3": "",
  "REMARK4": ""
}

EstEID.verify(pin, valuepromise)

Returns a Promise that resolves if PIN verification succeeds. Use EstEID.PIN1, EstEID.PIN2 and EstEID.PUK to indicate PIN type. valuepromise must resolve to the PIN value, as an ASCII string.

var pin = Promise.resolve('1234')
EstEID.verify(EstEID.PIN1, pin).then(
  () => console.log('PIN verified'),
  (e) => console.log('PIN verification failed', e)
)

There is a handy PIN wrapper for CLI application in cli.js

const cli = require('./cli.js')
EstEID.verify(EstEID.PIN1, cli.PIN('Please enter PIN1')).then(
  () => console.log('PIN verified'),
  (e) => console.log('PIN verification failed', e)
)

EstEID.getCertificate(type)

Returns a Promise that resolves to the certificate as a Buffer. Use EstEID.AUTH and EstEID.SIGN to indicate certificate type.

EstEID.getCertificate(EstEID.AUTH).then((cert) => {
   // do something with the certificate
})

EstEID.authenticate(challenge, pinpromise)

Returns a Promise that resolves to the result of RSA signature operation with the authentication key, as a Buffer. PIN promise, if provided, is resolved only if the card is in unauthenticated state.

EstEID.authenticate(challenge).then((cryptogram) => {
   // do something with the cryptogram
})

EstEID.sign(dtbs, pinpromise)

Returns a Promise that resolves to the result of RSA signature operation with the signing key, as a Buffer. PIN promise is required and is always resolved.

EstEID.sign(dtbs, Promise.resolve('12345')).then((signature) => {
   // do something with the signature
})

EstEID.decrypt(cryptogram, pinpromise)

Returns a Promise that resolves to the result of RSA decryption operation with the authentication key, as a Buffer. PIN promise, if provided, is resolved only if the card is in unauthenticated state.

EstEID.decrypt(cryptogram).then((plaintext) => {
   // do something with the plaintext
})

EstEID.getPINCounters(pin)

Returns a Promise that resolves to the remaining PIN tries for all PIN-s or the PIN specified. By default all remaining retries are returned in an array ([PIN1, PIN2, PUK]). If a single pin is given as a parameter, a single counter is returned.

EstEID.getPINCounters().then((triesleft) => {
   // do something with the tries left information
})

EstEID.getKeyCounters(key)

Returns a Promise that resolves to the key usage counters. By default both counters returned in an array ([AUTH, SIGN]). If a single key is given as a parameter, a single counter is returned.

EstEID.getKeyCounters().then((counters) => {
   // do something with the counters
})

esteid.js's People

Contributors

martinpaljak avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

esteid.js's Issues

'npm test pcsc' not works

Running npm test pcsc results in error. Error happening in the EstEID.authenticate method call:

pavlovdog@local:~/esteid.js$ npm test pcsc

> [email protected] test /home/pavlovdog/esteid.js
> node test-node.js "pcsc"

EstEID v0.0.5
                                
                                   ▄████████    ▄████████     ███        ▄████████  ▄█  ████████▄
                                  ███    ███   ███    ███ ▀█████████▄   ███    ███ ███  ███   ▀███
                                  ███    █▀    ███    █▀     ▀███▀▀██   ███    █▀  ███▌ ███    ███
                                 ▄███▄▄▄       ███            ███   ▀  ▄███▄▄▄     ███▌ ███    ███
                                ▀▀███▀▀▀     ▀███████████     ███     ▀▀███▀▀▀     ███▌ ███    ███
                                  ███    █▄           ███     ███       ███    █▄  ███  ███    ███
                                  ███    ███    ▄█    ███     ███       ███    ███ ███  ███   ▄███
                                  ██████████  ▄████████▀     ▄████▀     ██████████ █▀   ████████▀
                                
                                     EstEID for JS, version 0.0.5 by github.com/@martinpljak
                                                           
                                                           
                                                           
                                                           
Please connect a card reader and insert a card
READER  ACS ACR 38U-CCID 00 00
CARD ACS ACR 38U-CCID 00 00
Card in ACS ACR 38U-CCID 00 00 matches (3bfe1800008031fe45803180664090a4162a00830f9000ef)!
Personal data: {
  "SURNAME": "**********",
  "GIVEN_NAMES1": "**********",
  "GIVEN_NAMES2": "",
  "SEX": "M",
  "CITIZENSHIP": "**********",
  "DATE_OF_BIRTH": "**********",
  "PERSONAL_ID": "**********",
  "DOCUMENT_NR": "**********",
  "EXPIRY_DATE": "**********",
  "PLACE_OF_BIRTH": "**********",
  "ISSUING_DATE": "**********",
  "PERMIT_TYPE": "",
  "REMARK1": "**********",
  "REMARK2": "",
  "REMARK3": "",
  "REMARK4": ""
}
PIN retry counters:
PIN1=3 PIN2=3 PUK=3
Do PIN verification tests [y/n]: n
Certificate: **********,**********,********** digital signature
Certificate: **********,**********,********** authentication
Please enter PIN1: ****
Authentication failed:  Error: APDU SW check failed, SW 0x6700 not in 0x9000
    at /home/pavlovdog/esteid.js/apdu.js:59:13
    at <anonymous>
Some of the tests failed Error: APDU SW check failed, SW 0x6700 not in 0x9000
    at /home/pavlovdog/esteid.js/apdu.js:59:13
    at <anonymous>
Application failed Error: APDU SW check failed, SW 0x6700 not in 0x9000
    at /home/pavlovdog/esteid.js/apdu.js:59:13
    at <anonymous>
npm ERR! Test failed.  See above for more details.

I've replaced all sensetive information with **********. My specs:

$ uname -a
Linux local 4.15.0-24-generic #26~16.04.1-Ubuntu SMP Fri Jun 15 14:35:08 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
$ node -v
v8.11.3
$ npm -v
5.6.0

macOS sierra: SCardConnect sharing violation

on macOS sierra node test.js runs fine the first time but consecutive runs produce SCardConnect sharing violation error:

Please connect a card reader and insert a card
READER OMNIKEY CardMan 1021
CARD OMNIKEY CardMan 1021
Card in OMNIKEY CardMan 1021 matches (3bfe1800008031fe45803180664090a4162a00830f9000ef)!
Error: SCardConnect error: Sharing violation.(0x8010000b)
at Error (native)

decrypt function is missing PIN promise/check

Here is a patch, should I create a pull request?

--- ../esteid-dev/esteid.js    2017-04-29 15:46:20.000000000 +0300
+++ esteid.js   2017-04-27 10:59:02.000000000 +0300
@@ -242,8 +242,16 @@
             header[0] = chunks.length === 0 ? 0x00 : 0x10
             header[4] = chunk.length
             var cmd = Buffer.concat([header, chunk, Buffer.from([0x00])])
-            apdu.check(transmit(cmd)).then(function (r) {
-              if (chunks.length === 0) { return resolve(apdu.data(r)) } else { return decr() }
+            // verify PIN1 and decrypt
+            return eid.verify(eid.PIN1, pin).then(function () {
+              apdu.check(transmit(cmd)).then(function (r) {
+                if (chunks.length === 0) {
+                  return resolve(apdu.data(r))
+                }
+                else {
+                  return decr()
+                }
+              })
             }).catch(function (reason) {
               console.log('Decryption failed')
               reject(reason)

npm install not works - `node-gyp rebuild` error

I'm trying to follow all the instructions from the README and install module after cloning the repo. But there's an error on the npm install:

$ npm install

> [email protected] install /home/pavlovdog/esteid.js/node_modules/x509
> node-gyp rebuild

make: Entering directory '/home/pavlovdog/esteid.js/node_modules/x509/build'
  CXX(target) Release/obj.target/x509/src/addon.o
In file included from ../../nan/nan.h:194:0,
                 from ../include/x509.h:7,
                 from ../src/addon.cc:5:
../../nan/nan_maybe_43_inl.h: In function ‘Nan::Maybe<bool> Nan::ForceSet(v8::Local<v8::Object>, v8::Local<v8::Value>, v8::Local<v8::Value>, v8::PropertyAttribute)’:
../../nan/nan_maybe_43_inl.h:88:15: error: ‘class v8::Object’ has no member named ‘ForceSet’
   return obj->ForceSet(GetCurrentContext(), key, value, attribs);
               ^
../../nan/nan_maybe_43_inl.h: In function ‘Nan::MaybeLocal<v8::Object> Nan::CloneElementAt(v8::Local<v8::Array>, uint32_t)’:
../../nan/nan_maybe_43_inl.h:220:17: error: ‘class v8::Array’ has no member named ‘CloneElementAt’
   return array->CloneElementAt(GetCurrentContext(), index);
                 ^
In file included from ../../nan/nan_new.h:189:0,
                 from ../../nan/nan.h:200,
                 from ../include/x509.h:7,
                 from ../src/addon.cc:5:
../../nan/nan_implementation_12_inl.h: In static member function ‘static Nan::imp::FactoryBase<v8::BooleanObject>::return_t Nan::imp::Factory<v8::BooleanObject>::New(bool)’:
../../nan/nan_implementation_12_inl.h:40:38: error: no matching function for call to ‘v8::BooleanObject::New(bool&)’
   return v8::BooleanObject::New(value).As<v8::BooleanObject>();
                                      ^
In file included from /home/pavlovdog/.node-gyp/10.6.0/include/node/node.h:63:0,
                 from ../include/addon.h:4,
                 from ../src/addon.cc:4:
/home/pavlovdog/.node-gyp/10.6.0/include/node/v8.h:4948:23: note: candidate: static v8::Local<v8::Value> v8::BooleanObject::New(v8::Isolate*, bool)
   static Local<Value> New(Isolate* isolate, bool value);
                       ^
/home/pavlovdog/.node-gyp/10.6.0/include/node/v8.h:4948:23: note:   candidate expects 2 arguments, 1 provided
In file included from ../../nan/nan_new.h:189:0,
                 from ../../nan/nan.h:200,
                 from ../include/x509.h:7,
                 from ../src/addon.cc:5:
../../nan/nan_implementation_12_inl.h:40:60: error: expected primary-expression before ‘>’ token
   return v8::BooleanObject::New(value).As<v8::BooleanObject>();
                                                            ^
../../nan/nan_implementation_12_inl.h:40:62: error: expected primary-expression before ‘)’ token
   return v8::BooleanObject::New(value).As<v8::BooleanObject>();
                                                              ^
In file included from ../include/x509.h:7:0,
                 from ../src/addon.cc:5:
../../nan/nan.h: In function ‘v8::Local<v8::Value> Nan::MakeCallback(v8::Local<v8::Object>, v8::Local<v8::Function>, int, v8::Local<v8::Value>*)’:
../../nan/nan.h:821:60: warning: ‘v8::Local<v8::Value> node::MakeCallback(v8::Isolate*, v8::Local<v8::Object>, v8::Local<v8::Function>, int, v8::Local<v8::Value>*)’ is deprecated: Use MakeCallback(..., async_context) [-Wdeprecated-declarations]
         v8::Isolate::GetCurrent(), target, func, argc, argv);
                                                            ^
In file included from ../include/addon.h:4:0,
                 from ../src/addon.cc:4:
/home/pavlovdog/.node-gyp/10.6.0/include/node/node.h:172:50: note: declared here
                 NODE_EXTERN v8::Local<v8::Value> MakeCallback(
                                                  ^
/home/pavlovdog/.node-gyp/10.6.0/include/node/node.h:88:42: note: in definition of macro ‘NODE_DEPRECATED’
     __attribute__((deprecated(message))) declarator
                                          ^
In file included from ../include/x509.h:7:0,
                 from ../src/addon.cc:5:
../../nan/nan.h: In function ‘v8::Local<v8::Value> Nan::MakeCallback(v8::Local<v8::Object>, v8::Local<v8::String>, int, v8::Local<v8::Value>*)’:
../../nan/nan.h:835:62: warning: ‘v8::Local<v8::Value> node::MakeCallback(v8::Isolate*, v8::Local<v8::Object>, v8::Local<v8::String>, int, v8::Local<v8::Value>*)’ is deprecated: Use MakeCallback(..., async_context) [-Wdeprecated-declarations]
         v8::Isolate::GetCurrent(), target, symbol, argc, argv);
                                                              ^
In file included from ../include/addon.h:4:0,
                 from ../src/addon.cc:4:
/home/pavlovdog/.node-gyp/10.6.0/include/node/node.h:165:50: note: declared here
                 NODE_EXTERN v8::Local<v8::Value> MakeCallback(
                                                  ^
/home/pavlovdog/.node-gyp/10.6.0/include/node/node.h:88:42: note: in definition of macro ‘NODE_DEPRECATED’
     __attribute__((deprecated(message))) declarator
                                          ^
In file included from ../include/x509.h:7:0,
                 from ../src/addon.cc:5:
../../nan/nan.h: In function ‘v8::Local<v8::Value> Nan::MakeCallback(v8::Local<v8::Object>, const char*, int, v8::Local<v8::Value>*)’:
../../nan/nan.h:849:62: warning: ‘v8::Local<v8::Value> node::MakeCallback(v8::Isolate*, v8::Local<v8::Object>, const char*, int, v8::Local<v8::Value>*)’ is deprecated: Use MakeCallback(..., async_context) [-Wdeprecated-declarations]
         v8::Isolate::GetCurrent(), target, method, argc, argv);
                                                              ^
In file included from ../include/addon.h:4:0,
                 from ../src/addon.cc:4:
/home/pavlovdog/.node-gyp/10.6.0/include/node/node.h:158:50: note: declared here
                 NODE_EXTERN v8::Local<v8::Value> MakeCallback(
                                                  ^
/home/pavlovdog/.node-gyp/10.6.0/include/node/node.h:88:42: note: in definition of macro ‘NODE_DEPRECATED’
     __attribute__((deprecated(message))) declarator
                                          ^
In file included from ../include/x509.h:7:0,
                 from ../src/addon.cc:5:
../../nan/nan.h: In member function ‘v8::Local<v8::Value> Nan::Callback::Call_(v8::Isolate*, v8::Local<v8::Object>, int, v8::Local<v8::Value>*) const’:
../../nan/nan.h:1467:5: warning: ‘v8::Local<v8::Value> node::MakeCallback(v8::Isolate*, v8::Local<v8::Object>, v8::Local<v8::Function>, int, v8::Local<v8::Value>*)’ is deprecated: Use MakeCallback(..., async_context) [-Wdeprecated-declarations]
     ));
     ^
In file included from ../include/addon.h:4:0,
                 from ../src/addon.cc:4:
/home/pavlovdog/.node-gyp/10.6.0/include/node/node.h:172:50: note: declared here
                 NODE_EXTERN v8::Local<v8::Value> MakeCallback(
                                                  ^
/home/pavlovdog/.node-gyp/10.6.0/include/node/node.h:88:42: note: in definition of macro ‘NODE_DEPRECATED’
     __attribute__((deprecated(message))) declarator
                                          ^
In file included from ../include/x509.h:7:0,
                 from ../src/addon.cc:5:
../../nan/nan.h: In function ‘bool Nan::SetAccessor(v8::Local<v8::Object>, v8::Local<v8::String>, Nan::GetterCallback, Nan::SetterCallback, v8::Local<v8::Value>, v8::AccessControl, v8::PropertyAttribute)’:
../../nan/nan.h:1969:16: error: no matching function for call to ‘v8::Object::SetAccessor(v8::Local<v8::String>&, void (*&)(v8::Local<v8::Name>, const v8::PropertyCallbackInfo<v8::Value>&), void (*&)(v8::Local<v8::Name>, v8::Local<v8::Value>, const v8::PropertyCallbackInfo<void>&), v8::Local<v8::Object>&, v8::AccessControl&, v8::PropertyAttribute&)’
     , attribute);
                ^
In file included from /home/pavlovdog/.node-gyp/10.6.0/include/node/node.h:63:0,
                 from ../include/addon.h:4,
                 from ../src/addon.cc:4:
/home/pavlovdog/.node-gyp/10.6.0/include/node/v8.h:3266:37: note: candidate: v8::Maybe<bool> v8::Object::SetAccessor(v8::Local<v8::Context>, v8::Local<v8::Name>, v8::AccessorNameGetterCallback, v8::AccessorNameSetterCallback, v8::MaybeLocal<v8::Value>, v8::AccessControl, v8::PropertyAttribute, v8::SideEffectType)
   V8_WARN_UNUSED_RESULT Maybe<bool> SetAccessor(
                                     ^
/home/pavlovdog/.node-gyp/10.6.0/include/node/v8.h:3266:37: note:   no known conversion for argument 2 from ‘Nan::imp::NativeGetter {aka void (*)(v8::Local<v8::Name>, const v8::PropertyCallbackInfo<v8::Value>&)}’ to ‘v8::Local<v8::Name>’
x509.target.mk:102: recipe for target 'Release/obj.target/x509/src/addon.o' failed
make: *** [Release/obj.target/x509/src/addon.o] Error 1
make: Leaving directory '/home/pavlovdog/esteid.js/node_modules/x509/build'
gyp ERR! build error 
gyp ERR! stack Error: `make` failed with exit code: 2
gyp ERR! stack     at ChildProcess.onExit (/usr/lib/node_modules/npm/node_modules/node-gyp/lib/build.js:258:23)
gyp ERR! stack     at ChildProcess.emit (events.js:182:13)
gyp ERR! stack     at Process.ChildProcess._handle.onexit (internal/child_process.js:237:12)
gyp ERR! System Linux 4.15.0-24-generic
gyp ERR! command "/usr/bin/node" "/usr/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js" "rebuild"
gyp ERR! cwd /home/pavlovdog/esteid.js/node_modules/x509
gyp ERR! node -v v10.6.0
gyp ERR! node-gyp -v v3.6.2
gyp ERR! not ok 
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] install: `node-gyp rebuild`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the [email protected] install script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /home/pavlovdog/.npm/_logs/2018-07-12T13_05_42_226Z-debug.log

How can I fix it? I have already tried to remove ~/.node-gyp, node_modules and run npm update - didn't help, same error?

P.S. I'm using Ubuntu 16.04

$ uname -a
Linux local 4.15.0-24-generic #26~16.04.1-Ubuntu SMP Fri Jun 15 14:35:08 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
$ node -v
v10.6.0
$ npm -v
6.1.0

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.