github-af / SmartPGP

SmartPGP is a JavaCard implementation of the OpenPGP card specifications
GNU General Public License v2.0
229 stars 48 forks source link

Setting serial number? #52

Closed rpavlik closed 10 months ago

rpavlik commented 10 months ago

I can't seem to figure out how to set the serial number or get it to generate one. As such I assume it won't work very well if I have more than one of these cards. I'm using a J3R180 card, and as long as I manage gpg and pcscd fighting, I can get this output:

gpg --card-status
Reader ...........: 04E6:5116:53312211227478:0
Application ID ...: D276000124010304AFAF000000000000
Application type .: OpenPGP
Version ..........: 3.4
Manufacturer .....: unknown
Serial number ....: 00000000

I searched the repo but could not find references to card serial number other than in some test scripts. Is this something set with install parameters? custom APDUs? Theoretically generated from some unique on-card value?

I do see that gpg thinks the AID is D276000124010304AFAF000000000000 which ends in a lot of zeroes - do I customize the app AID to set the serial?

I am installing with gp --load ~/Downloads/SmartPGP-v1.22.2-jc304-rsa_up_to_4096.cap

rpavlik commented 10 months ago

Ahh, sorry for the confusing question. Looks like it is actually in the AID per the OpenPGP card spec, go figure.

Do you have any sample command lines to correctly install the applet with a non-zero serial number?

github-af commented 10 months ago

With gp and the released CAP files from SmartPGP, you can load and install SmartPGP with a custom serial number with a single command, e.g. to set the AID (which includes the serial number) of the created instance of the applet to d276000124010304c0decdf177610000:

gp --load SmartPGP-v1.22.2-jc304-rsa_up_to_4096.cap --package D27600012401 --applet D276000124010304AFAF000000000000 --create d276000124010304c0decdf177610000
martinpaljak commented 10 months ago

With gp and the released CAP files from SmartPGP, you can load and install SmartPGP with a custom serial number with a single command, e.g. to set the AID (which includes the serial number) of the created instance of the applet to d276000124010304c0decdf177610000:

gp --load SmartPGP-v1.22.2-jc304-rsa_up_to_4096.cap --package D27600012401 --applet D276000124010304AFAF000000000000 --create d276000124010304c0decdf177610000

The shorthand which should be:

 gp --install SmartPGP-v1.22.2-jc304-rsa_up_to_4096.cap --create d276000124010304c0decdf177610000
rpavlik commented 10 months ago

Awesome, thanks both of you so much!

I used the following Python script, though it does make a hex serial number instead of a BCD one like appears to be typical. It doesn't seem to break GPG, though.

#!/usr/bin/env python3
# Copyright 2023, Collabora, Ltd.
# SPDX-License-Identifier: MIT
#
# Original author: Rylie Pavlik <rylie.pavlik@collabora.com>
#
# Install SmartPGP to a JavaCard with GlobalPlatformPro,
# assigning a random serial number in one of the unmanaged ranges.
# If you are actually manufacturing OpenPGP cards based on this applet,
# you should get your own manufacturer ID and correctly assign serial
# numbers: do not use this script.

import secrets
import subprocess

# anything in fff0 to fffe is for unmanaged random assignment of serial numbers
_MANUFACTURER = "fff5"

# _CAPFILE = "SmartPGP-v1.22.2-jc304-rsa_up_to_4096.cap"
_CAPFILE = "SmartPGP-v1.22.2-jc304-without_sm-rsa_up_to_4096.cap"

def _make_card():
    # SN is 8 digits, so 4 bytes shown as hex
    sn = secrets.token_hex(4)
    aid = f"d276000124010304{_MANUFACTURER}{sn}0000"
    print(f"Assigning serial number {sn} for manufacturer {_MANUFACTURER}")
    # Assumes GlobalPlatformPro is callable with just "gp"
    subprocess.check_call(["gp", "--install", _CAPFILE, "--create", aid])

if __name__ == "__main__":
    _make_card()