Compare commits
10 Commits
c2d7070f2d
...
c289445f9f
Author | SHA1 | Date | |
---|---|---|---|
c289445f9f | |||
8b977953a3 | |||
64eed711d0 | |||
|
75f884de5d | ||
|
efdbcb6274 | ||
|
8b1463c399 | ||
|
faaa48c042 | ||
|
e84853414f | ||
|
0b43929a83 | ||
|
4fbafe513b |
56
.github/workflows/card-status.py
vendored
Normal file
56
.github/workflows/card-status.py
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# OpenPGPpy : Scan devices demo
|
||||
# Copyright (C) 2020 BitLogiK
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3 of the License.
|
||||
# This program 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 General Public License for more details.
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
|
||||
try:
|
||||
import OpenPGPpy
|
||||
except ModuleNotFoundError:
|
||||
# Import the OpenPGPpy from parent or current folder
|
||||
# Can run demo w/o OpenPGPpy installed (from root or demo folder)
|
||||
from sys import path
|
||||
|
||||
path.append(".")
|
||||
path.append("..")
|
||||
import OpenPGPpy
|
||||
|
||||
|
||||
def main():
|
||||
i = 0
|
||||
displayed = 0
|
||||
while True:
|
||||
try:
|
||||
current_card = OpenPGPpy.OpenPGPcard(reader_index=i)
|
||||
print("--------------------------------------------------------")
|
||||
print(f"OpenPGP card/reader : {current_card.name}")
|
||||
print(f"OpenPGP version : {current_card.pgpverstr}")
|
||||
print(
|
||||
f"Manufacturer : {current_card.manufacturer} ({current_card.manufacturer_id})"
|
||||
)
|
||||
print(
|
||||
f"Device serial : {current_card.serial} ({hex(current_card.serial)})"
|
||||
)
|
||||
displayed += 1
|
||||
i += 1
|
||||
except OpenPGPpy.ConnectionException as exc:
|
||||
if str(exc) != "No OpenPGP applet on this reader.":
|
||||
break
|
||||
i += 1
|
||||
if displayed == 0:
|
||||
print("No OpenPGP device available")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
54
.github/workflows/main.yml
vendored
Normal file
54
.github/workflows/main.yml
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
name: smartgpg-test-applet
|
||||
|
||||
# Run this workflow every time a new commit pushed to your repository
|
||||
on: push
|
||||
|
||||
jobs:
|
||||
applet_tests:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
# Checkout repository
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v2
|
||||
# Run actions
|
||||
# Compilation tests
|
||||
- name: applet tests
|
||||
shell: bash
|
||||
run: |
|
||||
# get dependencies
|
||||
echo "==== get dependencies";
|
||||
sudo apt-get install -y --no-install-recommends procps autoconf automake libtool m4 pkg-config help2man make gcc ant automake autotools-dev sudo wget gnupg software-properties-common maven git pcscd libpcsclite-dev opensc;
|
||||
sudo apt-get install -y python3-setuptools python3-pyscard python3-pyasn1;
|
||||
pip3 install OpenPGPpy;
|
||||
# get JavaCard SDKs
|
||||
echo "==== get JavaCard SDKs";
|
||||
git clone https://github.com/martinpaljak/oracle_javacard_sdks && mv oracle_javacard_sdks/jc303_kit/ /tmp/ && mv oracle_javacard_sdks/jc305u4_kit/ /tmp/ && rm -rf oracle_javacard_sdks;
|
||||
# compile SmartPGP
|
||||
echo "==== compile SmartPGP";
|
||||
cat build.xml | sed 's/<cap /<cap export="SmartPGPApplet" /' > /tmp/build.xml && mv /tmp/build.xml ./;
|
||||
JC_HOME=/tmp/jc303_kit/ ant;
|
||||
# clone jcardsim repository, compile and install
|
||||
echo "==== clone jcardsim repository, compile and install";
|
||||
git clone https://github.com/licel/jcardsim;
|
||||
cd jcardsim && export JC_CLASSIC_HOME=/tmp/jc305u4_kit/ && mvn initialize && mvn clean package && cd -;
|
||||
# clone vsmartcard, compile and install
|
||||
echo "==== clone vsmartcard, compile and install";
|
||||
git clone https://github.com/frankmorgner/vsmartcard.git;
|
||||
cd vsmartcard/virtualsmartcard && autoreconf --verbose --install && ./configure --sysconfdir=/etc && make && sudo make install && cd -;
|
||||
# relaunch PCSC
|
||||
echo "==== relaunch PCSC";
|
||||
sudo killall -KILL pcscd 2> /dev/null || true;
|
||||
sudo pcscd -fad 2>&1 > /tmp/log_pcsc &
|
||||
sleep 2;
|
||||
# launch jcardsim
|
||||
echo "==== launch jcardsim";
|
||||
java -cp jcardsim/target/jcardsim-3.0.5-SNAPSHOT.jar:SmartPGPApplet/smartpgp.jar com.licel.jcardsim.remote.VSmartCard .github/workflows/smartpgp.cfg 2>&1 > /tmp/log_jcardsim &
|
||||
sleep 5;
|
||||
# install SmartPGP
|
||||
echo "==== test SmartPGP";
|
||||
opensc-tool -l;
|
||||
opensc-tool -s 80b800001810d276000124010304AFAF000000000000050000020F0F00;
|
||||
# get card status
|
||||
python3 .github/workflows/card-status.py;
|
||||
# main tests
|
||||
python3 .github/workflows/test_SmartPGP.py;
|
47
.github/workflows/reset.py
vendored
Normal file
47
.github/workflows/reset.py
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# OpenPGPpy : Reset device demo
|
||||
# Copyright (C) 2020 BitLogiK
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3 of the License.
|
||||
# This program 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 General Public License for more details.
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
|
||||
import getpass
|
||||
|
||||
|
||||
try:
|
||||
import OpenPGPpy
|
||||
except ModuleNotFoundError:
|
||||
# Import the OpenPGPpy from parent or current folder
|
||||
# Can run demo w/o OpenPGPpy installed (from root or demo folder)
|
||||
from sys import path
|
||||
|
||||
path.append(".")
|
||||
path.append("..")
|
||||
import OpenPGPpy
|
||||
|
||||
|
||||
def main():
|
||||
mydevice = OpenPGPpy.OpenPGPcard()
|
||||
print("Enter the PUK to reset the", mydevice.name)
|
||||
PIN3 = "12345678" #getpass.getpass("Enter PIN3 (PUK) : ")
|
||||
try:
|
||||
mydevice.reset(PIN3)
|
||||
except OpenPGPpy.PGPCardException as exc:
|
||||
if exc.sw_code == 0x6982 or exc.sw_code == 0x6A80:
|
||||
print("Error: Wrong PUK")
|
||||
return
|
||||
print("Reset done.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
6
.github/workflows/smartpgp.cfg
vendored
Normal file
6
.github/workflows/smartpgp.cfg
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
com.licel.jcardsim.card.applet.0.AID=d276000124010304AFAF000000000000
|
||||
com.licel.jcardsim.card.applet.0.Class=fr.anssi.smartpgp.SmartPGPApplet
|
||||
com.licel.jcardsim.card.ATR=3B80800101
|
||||
com.licel.jcardsim.vsmartcard.host=localhost
|
||||
com.licel.jcardsim.vsmartcard.port=35963
|
||||
com.licel.jcardsim.randomdata.secure=1
|
372
.github/workflows/test_SmartPGP.py
vendored
Normal file
372
.github/workflows/test_SmartPGP.py
vendored
Normal file
@ -0,0 +1,372 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
from sys import path
|
||||
import subprocess
|
||||
import getpass
|
||||
import hashlib
|
||||
import tempfile
|
||||
|
||||
|
||||
path.append(".")
|
||||
import OpenPGPpy
|
||||
|
||||
|
||||
class BadTestResult(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def sha256(data):
|
||||
return hashlib.sha256(data).digest()
|
||||
|
||||
|
||||
def rsa_2048_pubkey_to_der(pubkey):
|
||||
# Add ASN1 DER header
|
||||
# RSA 2048
|
||||
header_modulus = "30820122300d06092a864886f70d01010105000382010f003082010a0282010100"
|
||||
header_exponent = "0203"
|
||||
|
||||
modulus = pubkey[9:265].hex()
|
||||
exponent = pubkey[267:].hex()
|
||||
|
||||
return bytes.fromhex(header_modulus + modulus + header_exponent + exponent)
|
||||
|
||||
|
||||
def check_rsa_2048_signature(message, signature, pubkeyd):
|
||||
pubkey = rsa_2048_pubkey_to_der(pubkeyd)
|
||||
fpk = tempfile.NamedTemporaryFile(delete=False)
|
||||
fpk.write(pubkey)
|
||||
fpk.close()
|
||||
fsig = tempfile.NamedTemporaryFile(delete=False)
|
||||
fsig.write(signature)
|
||||
fsig.close()
|
||||
verify_cmd = (
|
||||
f"openssl dgst -sha256 -keyform DER -verify {fpk.name} -signature {fsig.name}"
|
||||
)
|
||||
sigOK = False
|
||||
try:
|
||||
subprocess.run(
|
||||
verify_cmd, input=message, shell=True, check=True, stdout=subprocess.PIPE
|
||||
)
|
||||
sigOK = True
|
||||
except Exception:
|
||||
print("[-] ERROR in signature verification:")
|
||||
print(">>> openssl is required in path to check signatures")
|
||||
sigOK = False
|
||||
os.remove(fpk.name)
|
||||
os.remove(fsig.name)
|
||||
return sigOK
|
||||
|
||||
|
||||
def encrypt_rsa_2048(message, pubkeyd):
|
||||
pubkey = rsa_2048_pubkey_to_der(pubkeyd)
|
||||
fpk = tempfile.NamedTemporaryFile(delete=False)
|
||||
fpk.write(pubkey)
|
||||
fpk.close()
|
||||
fenc = tempfile.NamedTemporaryFile(delete=False)
|
||||
fenc.close()
|
||||
encrypt_cmd = (
|
||||
f"openssl rsautl -keyform DER -pubin -inkey {fpk.name} -pkcs -encrypt -out {fenc.name}"
|
||||
)
|
||||
try:
|
||||
subprocess.run(
|
||||
encrypt_cmd, input=message, shell=True, check=True, stdout=subprocess.PIPE
|
||||
)
|
||||
except Exception:
|
||||
print("[-] ERROR in encrpytion")
|
||||
print(">>> openssl is required in path to encrypt message")
|
||||
raise
|
||||
os.remove(fpk.name)
|
||||
fres = open(fenc.name, 'rb')
|
||||
res = fres.read()
|
||||
fres.close()
|
||||
os.remove(fenc.name)
|
||||
return bytes.fromhex("00") + res
|
||||
|
||||
|
||||
def test_rsa_2048_signature(token, PIN1, PIN3, repeat):
|
||||
print(f"[+] == Test RSA 2048 signature ({repeat} signatures) ==")
|
||||
|
||||
# Verify PIN3, required for the next command
|
||||
print("[+] Verify PIN3")
|
||||
token.verify_pin(3, PIN3)
|
||||
|
||||
# Setup RSA 2048 for SIG key
|
||||
print("[+] Set SIG key to RSA 2048")
|
||||
token.put_data("00C1", "010800001103")
|
||||
|
||||
# Generate key for SIG key
|
||||
print("[+] Generate SIG key")
|
||||
pubkey_card = token.gen_key("B600")
|
||||
|
||||
# Digest message and sign
|
||||
message = "Hello SmartPGP! Take that message.".encode("ascii")
|
||||
header_sha256 = "3031300D060960864801650304020105000420";
|
||||
hash = bytes.fromhex(header_sha256) + sha256(message)
|
||||
|
||||
for i in range(repeat):
|
||||
print(f"[+] Test #{i + 1}")
|
||||
|
||||
# Verify PIN1, required for signature
|
||||
token.verify_pin(1, PIN1)
|
||||
|
||||
print("[+] Sign SHA256 hash")
|
||||
sig_card = token.sign(hash)
|
||||
|
||||
print("[+] Verify signature")
|
||||
if not check_rsa_2048_signature(message, sig_card, pubkey_card):
|
||||
print("[-] BAD signature")
|
||||
raise BadTestResult
|
||||
|
||||
|
||||
def test_rsa_2048_decrypt(token, PIN1, PIN3, repeat):
|
||||
print(f"[+] == Test RSA 2048 decrypt ({repeat} deciphers) ==")
|
||||
|
||||
# Verify PIN3, required for the next command
|
||||
print("[+] Verify PIN3")
|
||||
token.verify_pin(3, PIN3)
|
||||
|
||||
# Setup RSA 2048 for DEC key
|
||||
print("[+] Set DEC key to RSA 2048")
|
||||
token.put_data("00C2", "010800001103")
|
||||
|
||||
# Generate key for DEC key
|
||||
print("[+] Generate DEC key")
|
||||
pubkey_card = token.gen_key("B800")
|
||||
|
||||
# Verify PIN2, required for decrypt
|
||||
token.verify_pin(2, PIN1)
|
||||
|
||||
# Cipher message
|
||||
message = "Hello SmartPGP! Take that message.".encode("ascii")
|
||||
|
||||
print("[+] Prepare encrypted message")
|
||||
encrypted = encrypt_rsa_2048(message, pubkey_card)
|
||||
|
||||
for i in range(repeat):
|
||||
print(f"[+] Test #{i + 1}")
|
||||
|
||||
print("[+] Decipher message")
|
||||
decrypted = token.decipher(encrypted)
|
||||
|
||||
print("[+] Verify message")
|
||||
if message == decrypted:
|
||||
print("[+] Good deciphering")
|
||||
else:
|
||||
print("[-] BAD deciphering")
|
||||
raise BadTestResult
|
||||
|
||||
|
||||
def test_rsa_2048(token, PIN1, PIN3, repeat):
|
||||
print("[+] === Test RSA 2048 ===")
|
||||
|
||||
test_rsa_2048_signature(token, PIN1, PIN3, repeat)
|
||||
|
||||
test_rsa_2048_decrypt(token, PIN1, PIN3, repeat)
|
||||
|
||||
|
||||
def ec_prime256v1_pubkey_to_der(pubkey):
|
||||
# Add ASN1 DER header (EC parameters)
|
||||
# ECP 256 r1 header
|
||||
header_hex = "3059301306072A8648CE3D020106082A8648CE3D030107034200"
|
||||
return bytes.fromhex(header_hex + pubkey.hex())
|
||||
|
||||
|
||||
def check_ec_prime256v1_signature(message, signature, pubkeyd):
|
||||
pubkey = ec_prime256v1_pubkey_to_der(pubkeyd)
|
||||
fpk = tempfile.NamedTemporaryFile(delete=False)
|
||||
fpk.write(pubkey)
|
||||
fpk.close()
|
||||
fsig = tempfile.NamedTemporaryFile(delete=False)
|
||||
fsig.write(signature)
|
||||
fsig.close()
|
||||
verify_cmd = (
|
||||
f"openssl dgst -sha256 -keyform DER -verify {fpk.name} -signature {fsig.name}"
|
||||
)
|
||||
sigOK = False
|
||||
try:
|
||||
subprocess.run(
|
||||
verify_cmd, input=message, shell=True, check=True, stdout=subprocess.PIPE
|
||||
)
|
||||
sigOK = True
|
||||
except Exception:
|
||||
print("[-] ERROR in signature verification")
|
||||
print(">>> openssl is required in path to check signatures")
|
||||
sigOK = False
|
||||
os.remove(fpk.name)
|
||||
os.remove(fsig.name)
|
||||
return sigOK
|
||||
|
||||
|
||||
def encrypt_ec_prime256v1(pubkeyd):
|
||||
pubkey = ec_prime256v1_pubkey_to_der(pubkeyd)
|
||||
fpub = tempfile.NamedTemporaryFile(delete=False)
|
||||
fpub.write(pubkey)
|
||||
fpub.close()
|
||||
|
||||
fpriv2 = tempfile.NamedTemporaryFile(delete=False)
|
||||
fpriv2.close()
|
||||
generate_private_cmd = (
|
||||
f"openssl genpkey -outform DER -out {fpriv2.name} -algorithm EC -pkeyopt ec_paramgen_curve:prime256v1 -pkeyopt ec_param_enc:named_curve"
|
||||
)
|
||||
try:
|
||||
subprocess.run(
|
||||
generate_private_cmd, shell=True, check=True, stdout=subprocess.PIPE
|
||||
)
|
||||
except Exception:
|
||||
print("[-] ERROR in encrpytion")
|
||||
print(">>> openssl is required in path to encrypt message")
|
||||
raise
|
||||
|
||||
fpub2 = tempfile.NamedTemporaryFile(delete=False)
|
||||
fpub2.close()
|
||||
generate_pub_cmd = (
|
||||
f"openssl pkey -pubout -inform DER -in {fpriv2.name} -outform DER -out {fpub2.name}"
|
||||
)
|
||||
try:
|
||||
subprocess.run(
|
||||
generate_pub_cmd, shell=True, check=True, stdout=subprocess.PIPE
|
||||
)
|
||||
except Exception:
|
||||
print("[-] ERROR in encrpytion")
|
||||
print(">>> openssl is required in path to encrypt message")
|
||||
raise
|
||||
|
||||
fenc = tempfile.NamedTemporaryFile(delete=False)
|
||||
fenc.close()
|
||||
generate_ecdh_cmd = (
|
||||
f"openssl pkeyutl -derive -out {fenc.name} -keyform DER -inkey {fpriv2.name} -peerform DER -peerkey {fpub.name}"
|
||||
)
|
||||
try:
|
||||
subprocess.run(
|
||||
generate_ecdh_cmd, shell=True, check=True, stdout=subprocess.PIPE
|
||||
)
|
||||
except Exception:
|
||||
print("[-] ERROR in encrpytion")
|
||||
print(">>> openssl is required in path to encrypt message")
|
||||
raise
|
||||
|
||||
f = open(fpub2.name, 'rb')
|
||||
pub2 = f.read()
|
||||
pub2 = pub2[26:]
|
||||
f.close()
|
||||
|
||||
f = open(fenc.name, 'rb')
|
||||
enc = f.read()
|
||||
f.close()
|
||||
|
||||
os.remove(fpub.name)
|
||||
os.remove(fpriv2.name)
|
||||
os.remove(fpub2.name)
|
||||
os.remove(fenc.name)
|
||||
|
||||
return (bytes.fromhex("A646") + bytes.fromhex("7F4943") + bytes.fromhex("8641") + pub2, enc)
|
||||
|
||||
|
||||
def test_ec_prime256v1_signature(token, PIN1, PIN3, repeat):
|
||||
print(f"[+] == Test EC prime256v1 signature ({repeat} signatures) ==")
|
||||
|
||||
# Verify PIN3, required for the next command
|
||||
print("[+] Verify PIN3")
|
||||
token.verify_pin(3, PIN3)
|
||||
|
||||
# Setup EC prime256v1 for SIG key
|
||||
print("[+] Set SIG key to EC prime256v1")
|
||||
token.put_data("00C1", "132A8648CE3D030107")
|
||||
|
||||
# Generate key for SIG key
|
||||
print("[+] Generate SIG key")
|
||||
pubkey_card = token.gen_key("B600")
|
||||
pubkey_card = pubkey_card[-65:]
|
||||
|
||||
# Digest message and sign
|
||||
message = "Hello SmartPGP! Take that message.".encode("ascii")
|
||||
hash = sha256(message)
|
||||
|
||||
for i in range(repeat):
|
||||
print(f"[+] Test #{i + 1}")
|
||||
|
||||
# Verify PIN1, required for signature
|
||||
token.verify_pin(1, PIN1)
|
||||
|
||||
print("[+] Sign SHA256 hash")
|
||||
sig_card = token.sign_ec_der(hash)
|
||||
|
||||
print("[+] Verify signature")
|
||||
if not check_ec_prime256v1_signature(message, sig_card, pubkey_card):
|
||||
print("[-] BAD signature")
|
||||
raise BadTestResult
|
||||
|
||||
|
||||
def test_ec_prime256v1_decrypt(token, PIN1, PIN3, repeat):
|
||||
print(f"[+] == Test EC prime256v1 decrypt ({repeat} deciphers) ==")
|
||||
|
||||
# Verify PIN3, required for the next command
|
||||
print("[+] Verify PIN3")
|
||||
token.verify_pin(3, PIN3)
|
||||
|
||||
# Setup EC prime256v1 for DEC key
|
||||
print("[+] Set DEC key to EC prime256v1")
|
||||
token.put_data("00C2", "122A8648CE3D030107")
|
||||
|
||||
# Generate key for DEC key
|
||||
print("[+] Generate DEC key")
|
||||
pubkey_card = token.gen_key("B800")
|
||||
pubkey_card = pubkey_card[-65:]
|
||||
|
||||
# Verify PIN2, required for decrypt
|
||||
token.verify_pin(2, PIN1)
|
||||
|
||||
print("[+] Prepare ECDH")
|
||||
(encrypted, secret) = encrypt_ec_prime256v1(pubkey_card)
|
||||
|
||||
for i in range(repeat):
|
||||
print(f"[+] Test #{i + 1}")
|
||||
|
||||
print("[+] Decipher (compute ECDH secret)")
|
||||
decrypted = token.decipher(encrypted)
|
||||
|
||||
print("[+] Verify message")
|
||||
if secret == decrypted:
|
||||
print("[+] Good deciphering")
|
||||
else:
|
||||
print("[-] BAD deciphering")
|
||||
raise BadTestResult
|
||||
|
||||
|
||||
def test_ec_prime256v1(token, PIN1, PIN3, repeat):
|
||||
print("[+] === Test EC prime256v1 ===")
|
||||
|
||||
test_ec_prime256v1_signature(token, PIN1, PIN3, repeat)
|
||||
|
||||
test_ec_prime256v1_decrypt(token, PIN1, PIN3, repeat)
|
||||
|
||||
|
||||
def main(rsa, ec, repeat):
|
||||
# True/False == with/without debug
|
||||
token = OpenPGPpy.OpenPGPcard(False)
|
||||
|
||||
PIN1 = "123456"
|
||||
PIN3 = "12345678"
|
||||
|
||||
if rsa:
|
||||
test_rsa_2048(token, PIN1, PIN3, repeat)
|
||||
|
||||
if ec:
|
||||
test_ec_prime256v1(token, PIN1, PIN3, repeat)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
main(rsa=True, ec=False, repeat=200)
|
||||
except OpenPGPpy.openpgp_card.ConnectionException:
|
||||
print(f"[-] FAILED to find OpenPGP token")
|
||||
exit(1)
|
||||
except OpenPGPpy.PGPCardException as exc:
|
||||
if exc.sw_code != 0x9000:
|
||||
print(f"[-] FAILED with: 0x{exc.sw_code:02x}")
|
||||
exit(2)
|
||||
except BadTestResult:
|
||||
print(f"[-] FAILED test")
|
||||
exit(3)
|
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
*.jar
|
||||
*.cap
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
[submodule "sdks"]
|
||||
path = sdks
|
||||
url = https://github.com/martinpaljak/oracle_javacard_sdks
|
@ -462,17 +462,17 @@ class CardConnectionContext:
|
||||
raise AdminPINFailed
|
||||
####### step 3bis
|
||||
if nresetting_code != None:
|
||||
set_resetting_code(self.connection, nresetting_code)
|
||||
(_,sw1,sw2) = set_resetting_code(self.connection, nresetting_code)
|
||||
if sw1!=0x90 or sw2!=0x00:
|
||||
print("set_resetting_code failed")
|
||||
return
|
||||
####### step 4
|
||||
change_reference_data_pw1(self.connection, ascii_encode_pin(pw1), list(npw1))
|
||||
(sw1,sw2) = change_reference_data_pw1(self.connection, ascii_encode_pin(pw1), list(npw1))
|
||||
if sw1!=0x90 or sw2!=0x00:
|
||||
print("change_reference_data_pw1 failed")
|
||||
return
|
||||
####### step 4bis
|
||||
change_reference_data_pw3(self.connection, ascii_encode_pin(pw3), list(npw3))
|
||||
(sw1,sw2) = change_reference_data_pw3(self.connection, ascii_encode_pin(pw3), list(npw3))
|
||||
if sw1!=0x90 or sw2!=0x00:
|
||||
print("change_reference_data_pw3 failed")
|
||||
return
|
||||
|
25
build.xml
25
build.xml
@ -1,13 +1,18 @@
|
||||
<?xml version="1.0"?>
|
||||
<project name="smartpgp" default="convert" basedir=".">
|
||||
<description>Ant build for SmartPGP applet</description>
|
||||
<get src="https://github.com/martinpaljak/ant-javacard/releases/download/v20.03.25/ant-javacard.jar" dest="." skipexisting="true"/>
|
||||
<taskdef name="javacard" classname="pro.javacard.ant.JavaCard" classpath="ant-javacard.jar"/>
|
||||
<target name="convert">
|
||||
<javacard>
|
||||
<cap output="SmartPGPApplet.cap" sources="src" aid="d27600012401" version="1.0">
|
||||
<applet class="fr.anssi.smartpgp.SmartPGPApplet" aid="d276000124010304AFAF000000000000"/>
|
||||
</cap>
|
||||
</javacard>
|
||||
</target>
|
||||
<description>Ant build for SmartPGP applet</description>
|
||||
|
||||
<!-- Add JC303 SDK for JCOP 3.0.1 -->
|
||||
<property name="JC303" value="sdks/jc303_kit"/>
|
||||
|
||||
<get src="https://github.com/martinpaljak/ant-javacard/releases/download/v20.03.25/ant-javacard.jar" dest="." skipexisting="true"/>
|
||||
<taskdef name="javacard" classname="pro.javacard.ant.JavaCard" classpath="ant-javacard.jar"/>
|
||||
|
||||
<target name="convert">
|
||||
<javacard>
|
||||
<cap jckit="${JC303}" output="SmartPGPApplet.cap" sources="src" aid="d27600012401" version="1.0">
|
||||
<applet class="fr.anssi.smartpgp.SmartPGPApplet" aid="d276000124010304c0deedb522560000"/>
|
||||
</cap>
|
||||
</javacard>
|
||||
</target>
|
||||
</project>
|
||||
|
@ -2,15 +2,6 @@ diff --git a/src/fr/anssi/smartpgp/Constants.java b/src/fr/anssi/smartpgp/Consta
|
||||
index b3c0f80..2ee1107 100644
|
||||
--- a/src/fr/anssi/smartpgp/Constants.java
|
||||
+++ b/src/fr/anssi/smartpgp/Constants.java
|
||||
@@ -30,7 +30,7 @@ public final class Constants {
|
||||
protected static final short INTERNAL_BUFFER_MAX_LENGTH =
|
||||
(short)0x500;
|
||||
|
||||
- protected static final short APDU_MAX_LENGTH = (short)256;
|
||||
+ protected static final short APDU_MAX_LENGTH = (short)0x400;
|
||||
|
||||
protected static final byte[] KEY_DERIVATION_FUNCTION_DEFAULT = {
|
||||
(byte)0x81, (byte)0x01, (byte)0x00
|
||||
@@ -149,7 +149,7 @@ public final class Constants {
|
||||
(byte)0x73, /* card capabilities */
|
||||
(byte)0xC0, /* 1st byte: "methods supported" see ISO 7816-4 */
|
||||
@ -20,25 +11,3 @@ index b3c0f80..2ee1107 100644
|
||||
|
||||
(byte)0x05, /* status indicator byte : operational state */
|
||||
(byte)0x90, /* SW1 */
|
||||
diff --git a/src/fr/anssi/smartpgp/SmartPGPApplet.java b/src/fr/anssi/smartpgp/SmartPGPApplet.java
|
||||
index c47870f..78d446d 100644
|
||||
--- a/src/fr/anssi/smartpgp/SmartPGPApplet.java
|
||||
+++ b/src/fr/anssi/smartpgp/SmartPGPApplet.java
|
||||
@@ -25,7 +25,7 @@ import javacard.security.*;
|
||||
import javacardx.apdu.*;
|
||||
import javacardx.crypto.*;
|
||||
|
||||
-public final class SmartPGPApplet extends Applet {
|
||||
+public final class SmartPGPApplet extends Applet implements ExtendedLength {
|
||||
|
||||
private final Persistent data;
|
||||
|
||||
@@ -104,7 +104,7 @@ public final class SmartPGPApplet extends Applet {
|
||||
short blen = apdu.setIncomingAndReceive();
|
||||
|
||||
final short lc = apdu.getIncomingLength();
|
||||
- final short offcdata = ISO7816.OFFSET_CDATA;
|
||||
+ final short offcdata = apdu.getOffsetCdata();
|
||||
|
||||
short off = transients.chainingInputLength();
|
||||
|
||||
|
1
sdks
Submodule
1
sdks
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit e305a1a0b9bf6b9a8b0c91a9aad8d73537e7ff1b
|
@ -27,7 +27,7 @@ public final class Constants {
|
||||
protected static final short INTERNAL_BUFFER_MAX_LENGTH =
|
||||
(short)0x500;
|
||||
|
||||
protected static final short APDU_MAX_LENGTH = (short)256;
|
||||
protected static final short APDU_MAX_LENGTH = (short)0x400;
|
||||
|
||||
protected static final byte[] KEY_DERIVATION_FUNCTION_DEFAULT = {
|
||||
(byte)0x81, (byte)0x01, (byte)0x00
|
||||
|
@ -236,8 +236,8 @@ public final class Persistent {
|
||||
Common.beginTransaction(isRegistering);
|
||||
user_pin_length = (byte)Constants.USER_PIN_DEFAULT.length;
|
||||
user_pin.update(Constants.USER_PIN_DEFAULT, (short)0, user_pin_length);
|
||||
user_pin.resetAndUnblock();
|
||||
Common.commitTransaction(isRegistering);
|
||||
user_pin.resetAndUnblock();
|
||||
|
||||
Common.beginTransaction(isRegistering);
|
||||
user_puk_length = (short)0;
|
||||
@ -253,8 +253,8 @@ public final class Persistent {
|
||||
Common.beginTransaction(isRegistering);
|
||||
admin_pin_length = (byte)Constants.ADMIN_PIN_DEFAULT.length;
|
||||
admin_pin.update(Constants.ADMIN_PIN_DEFAULT, (short)0, admin_pin_length);
|
||||
admin_pin.resetAndUnblock();
|
||||
Common.commitTransaction(isRegistering);
|
||||
admin_pin.resetAndUnblock();
|
||||
|
||||
isTerminated = false;
|
||||
}
|
||||
|
@ -23,8 +23,9 @@ package fr.anssi.smartpgp;
|
||||
import javacard.framework.*;
|
||||
import javacard.security.*;
|
||||
import javacardx.crypto.*;
|
||||
import javacardx.apdu.ExtendedLength;
|
||||
|
||||
public final class SmartPGPApplet extends Applet {
|
||||
public final class SmartPGPApplet extends Applet implements ExtendedLength {
|
||||
|
||||
private final Common common;
|
||||
private final Persistent data;
|
||||
@ -100,7 +101,7 @@ public final class SmartPGPApplet extends Applet {
|
||||
short blen = apdu.setIncomingAndReceive();
|
||||
|
||||
final short lc = apdu.getIncomingLength();
|
||||
final short offcdata = ISO7816.OFFSET_CDATA;
|
||||
final short offcdata = apdu.getOffsetCdata();
|
||||
|
||||
short off = transients.chainingInputLength();
|
||||
|
||||
@ -766,10 +767,17 @@ public final class SmartPGPApplet extends Applet {
|
||||
|
||||
case (byte)0x02:
|
||||
assertAdmin();
|
||||
if((lc < Constants.USER_PIN_MIN_SIZE) ||
|
||||
(lc > Constants.USER_PIN_MAX_SIZE)) {
|
||||
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
|
||||
return;
|
||||
if(data.keyDerivationIsActive()) {
|
||||
if(lc != data.keyDerivationSize()) {
|
||||
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if((lc < Constants.USER_PIN_MIN_SIZE) ||
|
||||
(lc > Constants.USER_PIN_MAX_SIZE)) {
|
||||
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
|
||||
return;
|
||||
}
|
||||
}
|
||||
transients.setUserPinMode81(false);
|
||||
transients.setUserPinMode82(false);
|
||||
@ -1141,10 +1149,17 @@ public final class SmartPGPApplet extends Applet {
|
||||
|
||||
case Constants.TAG_RESETTING_CODE:
|
||||
assertAdmin();
|
||||
if((lc < Constants.USER_PUK_MIN_SIZE) ||
|
||||
(lc > Constants.USER_PUK_MAX_SIZE)) {
|
||||
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
|
||||
return;
|
||||
if(data.keyDerivationIsActive()) {
|
||||
if(lc != data.keyDerivationSize()) {
|
||||
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if((lc < Constants.USER_PUK_MIN_SIZE) ||
|
||||
(lc > Constants.USER_PUK_MAX_SIZE)) {
|
||||
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
|
||||
return;
|
||||
}
|
||||
}
|
||||
JCSystem.beginTransaction();
|
||||
data.user_puk_length = (byte)lc;
|
||||
|
Loading…
Reference in New Issue
Block a user