Skip to content

Commit

Permalink
Enable ECDH support and partial ECDSA
Browse files Browse the repository at this point in the history
  • Loading branch information
Alex Wilson committed Sep 30, 2017
1 parent 69dc514 commit 92959e3
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 20 deletions.
4 changes: 4 additions & 0 deletions README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ What works:

* OpenSC, MacOS (`piv.tokend` for login), Windows PIV
* RSA-1024 and -2048 key generation on card, signing
* EC P-256 key generation (but no ECDSA)
* EC Diffie-Hellman on P-256 (not working on all cards)
* PINs and change of PIN, PUK reset
* Some https://developers.yubico.com/PIV/Introduction/Yubico_extensions.html[
YubiKeyPIV-compatible extensions] are implemented and working:
Expand All @@ -26,6 +28,8 @@ What works:
What doesn't work:

* ECDSA (probably not fixable without JavaCard 3.0.5 or proprietary APIs)
* There is partial support for it in the code, but it will double-hash
input data unless client software explicitly works around it.
* Yubikey extensions (TODO):
- Set management key
- Import asymmetric key
Expand Down
32 changes: 17 additions & 15 deletions src/net/cooperi/pivapplet/ECParams.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,20 @@ public class ECParams {
public final static byte ALG_ECDSA_SHA_256 = (byte)33;

public static final byte[] nistp256_p = {
(byte)0x0, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
(byte)0x0, (byte)0x0, (byte)0x0, (byte)0x1, (byte)0x0, (byte)0x0,
(byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x0,
(byte)0x0, (byte)0x0, (byte)0x1, (byte)0x0, (byte)0x0, (byte)0x0,
(byte)0x0, (byte)0x0, (byte)0x0, (byte)0x0, (byte)0x0, (byte)0x0,
(byte)0x0, (byte)0x0, (byte)0x0, (byte)0x0, (byte)0xff, (byte)0xff,
(byte)0x0, (byte)0x0, (byte)0x0, (byte)0xff, (byte)0xff, (byte)0xff,
(byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
(byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff
(byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff
};
public static final byte[] nistp256_a = {
(byte)0x0, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
(byte)0x0, (byte)0x0, (byte)0x0, (byte)0x1, (byte)0x0, (byte)0x0,
(byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x0,
(byte)0x0, (byte)0x0, (byte)0x1, (byte)0x0, (byte)0x0, (byte)0x0,
(byte)0x0, (byte)0x0, (byte)0x0, (byte)0x0, (byte)0x0, (byte)0x0,
(byte)0x0, (byte)0x0, (byte)0x0, (byte)0x0, (byte)0xff, (byte)0xff,
(byte)0x0, (byte)0x0, (byte)0x0, (byte)0xff, (byte)0xff, (byte)0xff,
(byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
(byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xfc
(byte)0xff, (byte)0xff, (byte)0xff, (byte)0xfc
};
public static final byte[] nistp256_b = {
(byte)0x5a, (byte)0xc6, (byte)0x35, (byte)0xd8, (byte)0xaa,
Expand All @@ -39,11 +39,13 @@ public class ECParams {
(byte)0x60, (byte)0x4b
};
public static final byte[] nistp256_R = {
(byte)0x0, (byte)0xc4, (byte)0x9d, (byte)0x36, (byte)0x8,
(byte)0x86, (byte)0xe7, (byte)0x4, (byte)0x93, (byte)0x6a,
(byte)0x66, (byte)0x78, (byte)0xe1, (byte)0x13, (byte)0x9d,
(byte)0x26, (byte)0xb7, (byte)0x81, (byte)0x9f, (byte)0x7e,
(byte)0x90
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0x00,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xBC, (byte)0xE6, (byte)0xFA, (byte)0xAD,
(byte)0xA7, (byte)0x17, (byte)0x9E, (byte)0x84, (byte)0xF3,
(byte)0xB9, (byte)0xCA, (byte)0xC2, (byte)0xFC, (byte)0x63,
(byte)0x25, (byte)0x51
};
/*public static final byte[] nistp256_n = {
(byte)0x0, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
Expand Down Expand Up @@ -74,8 +76,8 @@ public static void setCurveParameters(ECKey eckey) {
nistp256_p, (short)0, (short)(nistp256_p.length));
eckey.setA(nistp256_a, (short)0, (short)(nistp256_a.length));
eckey.setB(nistp256_b, (short)0, (short)(nistp256_b.length));
eckey.setR(nistp256_R, (short)0, (short)(nistp256_R.length));
eckey.setG(nistp256_G, (short)0, (short)(nistp256_G.length));
eckey.setK((short)1);
eckey.setR(nistp256_R, (short)0, (short)(nistp256_R.length));
//eckey.setK((short)1);
}
}
71 changes: 66 additions & 5 deletions src/net/cooperi/pivapplet/PivApplet.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import javacard.security.DESKey;
import javacard.security.Key;
import javacard.security.KeyBuilder;
import javacard.security.KeyAgreement;
import javacard.security.KeyPair;
import javacard.security.PrivateKey;
import javacard.security.PublicKey;
Expand Down Expand Up @@ -85,8 +86,8 @@ public class PivApplet extends Applet implements ExtendedLength
private static final byte INS_IMPORT_ASYM = (byte)0xfe;
private static final byte INS_GET_VER = (byte)0xfd;

private static final short RAM_BUF_SIZE = (short)1200;
private static final short MAX_CERT_SIZE = (short)1100;
private static final short RAM_BUF_SIZE = (short)1000;
private static final short MAX_CERT_SIZE = (short)900;

private static final boolean USE_EXT_LEN = false;
private static final byte RBSTAT_SEND_REM = (byte)0;
Expand All @@ -112,6 +113,7 @@ public class PivApplet extends Applet implements ExtendedLength
private Cipher rsaPkcs1 = null;
private Signature ecdsaP256Sha = null;
private Signature ecdsaP256Sha256 = null;
private KeyAgreement ecdh = null;

private PivSlot slot9a = null, slot9b = null, slot9c = null,
slot9d = null, slot9e = null;
Expand Down Expand Up @@ -144,6 +146,8 @@ public class PivApplet extends Applet implements ExtendedLength
private static final byte TAG_CERT_9D = (byte)0x0B;
private static final byte TAG_CERT_9E = (byte)0x01;

private static final byte ALG_EC_SVDP_DH_PLAIN = (byte)3;

public static void
install(byte[] info, short off, byte len)
{
Expand Down Expand Up @@ -173,6 +177,25 @@ public class PivApplet extends Applet implements ExtendedLength
throw (ex);
}

try {
ecdh = KeyAgreement.getInstance(ALG_EC_SVDP_DH_PLAIN,
false);
} catch (CryptoException ex) {
if (ex.getReason() != CryptoException.NO_SUCH_ALGORITHM)
throw (ex);
}

if (ecdh == null) {
try {
ecdh = KeyAgreement.getInstance(
KeyAgreement.ALG_EC_SVDP_DH, false);
} catch (CryptoException ex) {
if (ex.getReason() !=
CryptoException.NO_SUCH_ALGORITHM)
throw (ex);
}
}

ramBuf = JCSystem.makeTransientByteArray(RAM_BUF_SIZE,
JCSystem.CLEAR_ON_RESET);
rbStat = JCSystem.makeTransientShortArray((short)3,
Expand Down Expand Up @@ -588,14 +611,14 @@ public class PivApplet extends Applet implements ExtendedLength

tlv.setTarget(ramBuf);

tlv.push64k((short)0x7F49);

switch (alg) {
case PIV_ALG_RSA1024:
case PIV_ALG_RSA2048:
RSAPublicKey rpubk =
(RSAPublicKey)slot.asym.getPublic();

tlv.push64k((short)0x7F49);

tlv.push64k((byte)0x81);
cLen = rpubk.getModulus(ramBuf, tlv.offset());
tlv.write(cLen);
Expand All @@ -610,7 +633,9 @@ public class PivApplet extends Applet implements ExtendedLength
ECPublicKey epubk =
(ECPublicKey)slot.asym.getPublic();

tlv.push256((byte)0x86);
tlv.push((short)0x7F49);

tlv.push((byte)0x86);
cLen = epubk.getW(ramBuf, tlv.offset());
tlv.write(cLen);
tlv.pop();
Expand Down Expand Up @@ -857,6 +882,42 @@ public class PivApplet extends Applet implements ExtendedLength
break;

case GA_TAG_RESPONSE:
if (tag == GA_TAG_EXP) {
if (alg != PIV_ALG_ECCP256) {
ISOException.throwIt(
ISO7816.SW_WRONG_DATA);
return;
}
if ((key == (byte)0x9b &&
!slot9b.flags[PivSlot.F_UNLOCKED]) ||
!slot.checkPin(pivPin)) {
ISOException.throwIt(
ISO7816.
SW_SECURITY_STATUS_NOT_SATISFIED);
return;
}
cLen = 256;
if ((short)(RAM_BUF_SIZE - cLen) < lc) {
ISOException.throwIt(ISO7816.SW_FILE_FULL);
return;
}
lc = (short)(RAM_BUF_SIZE - cLen);

ecdh.init(slot.asym.getPrivate());
cLen = ecdh.generateSecret(ramBuf, tlv.offset(),
tlv.tagLength(), ramBuf, lc);

tlv.setTarget(ramBuf);

tlv.push((byte)0x7C, (short)(cLen + 4));
tlv.push(GA_TAG_RESPONSE, cLen);
tlv.write(ramBuf, lc, cLen);
tlv.pop();

len = tlv.pop();
sendRamBuf(apdu, len);
break;
}
if (tag != GA_TAG_CHALLENGE) {
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
return;
Expand Down

0 comments on commit 92959e3

Please sign in to comment.