Compare commits

..

2 commits

2 changed files with 13 additions and 5 deletions

View file

@ -16,6 +16,10 @@ To sign using a PIV-II smartcard such as the Yubikey, install `pkcs11-tool` from
marginaltool -e pkcs11 -i <KEY ID> bc-digsign://sign?… marginaltool -e pkcs11 -i <KEY ID> bc-digsign://sign?…
If you need too specify a different PKCS#11 module, like `/usr/local/lib/libykcs11.so` for the Yubikey, set the module argument by running
marginaltool -e pkcs11 -m <MODULE PATH> -i <KEY ID> bc-digsign://sign?…
The script will prompt for the PIN to unlock the smartcard. To find the key ID, run The script will prompt for the PIN to unlock the smartcard. To find the key ID, run
pkcs11-tool -O pkcs11-tool -O

View file

@ -43,7 +43,10 @@ def init(args):
args.id = config.get(args.url, 'id', fallback=None) args.id = config.get(args.url, 'id', fallback=None)
if not args.id: if not args.id:
raise Exception('key ID not specified') raise Exception('key ID not specified')
args.cert = base64.b64encode(subprocess.run(['pkcs11-tool', '--read-object', '--type', 'cert', '--id', args.id], capture_output=True).stdout).decode() if not args.module:
args.module = config.get(args.module, 'module')
args.module = ["--module", str(pathlib.Path(args.module))] if args.module else []
args.cert = base64.b64encode(subprocess.run(['pkcs11-tool'] + args.module + ['--read-object', '--type', 'cert', '--id', args.id], capture_output=True).stdout).decode()
# read the PIN once to avoid prompting for each document # read the PIN once to avoid prompting for each document
import tkinter.simpledialog # only needed for PIN entry import tkinter.simpledialog # only needed for PIN entry
@ -58,7 +61,7 @@ def sign(b64data, args):
if not args.keyfile: if not args.keyfile:
raise Exception('keyfile not specified') raise Exception('keyfile not specified')
cmd = ['openssl', 'pkeyutl', '-sign', '-inkey', args.keyfile, '-pkeyopt', 'digest:sha256'] cmd = ['openssl', 'pkeyutl', '-sign', '-inkey', args.keyfile, '-pkeyopt', 'digest:sha256']
env = None env = {}
data = base64.b64decode(b64data) data = base64.b64decode(b64data)
case 'pkcs11': case 'pkcs11':
@ -72,14 +75,14 @@ def sign(b64data, args):
'SHA-384': '3041300d060960864801650304020205000430', 'SHA-384': '3041300d060960864801650304020205000430',
'SHA-512': '3051300d060960864801650304020305000440' 'SHA-512': '3051300d060960864801650304020305000440'
} }
cmd = ['pkcs11-tool', '--id', args.id, '-s', '-m', 'RSA-PKCS', '-p', 'env:PIN'] cmd = ['pkcs11-tool'] + args.module + ['--id', args.id, '-s', '-m', 'RSA-PKCS', '-p', 'env:PIN']
env = {'PIN': args.pin} env = {'PIN': args.pin}
data = bytes.fromhex(digest_info['SHA-256']) + base64.b64decode(b64data) data = bytes.fromhex(digest_info['SHA-256']) + base64.b64decode(b64data)
case '_': case '_':
raise Exception(f'invalid engine {args.engine}') raise Exception(f'invalid engine {args.engine}')
p = subprocess.run(cmd, env=env, input=data, capture_output=True) p = subprocess.run(cmd, env=os.environ | env, input=data, capture_output=True)
if p.returncode != 0: if p.returncode != 0:
raise Exception(f'could not sign data: {p.stderr.decode()}') raise Exception(f'could not sign data: {p.stderr.decode()}')
@ -91,7 +94,8 @@ if __name__ == '__main__':
parser.add_argument('-e', '--engine', choices=('file', 'pkcs11'), help='use key file or PKCS11 token?') parser.add_argument('-e', '--engine', choices=('file', 'pkcs11'), help='use key file or PKCS11 token?')
parser.add_argument('-k', '--keyfile', type=pathlib.Path, help='key file') parser.add_argument('-k', '--keyfile', type=pathlib.Path, help='key file')
parser.add_argument('-c', '--certfile', type=pathlib.Path, help='certificate file') parser.add_argument('-c', '--certfile', type=pathlib.Path, help='certificate file')
parser.add_argument('-i', '--id', type=int, metavar='<KEY ID>', help='key ID on PKCS11 token') parser.add_argument('-m', '--module', type=pathlib.Path, help='PKCS11 module file')
parser.add_argument('-i', '--id', type=str, metavar='<KEY ID>', help='key ID on PKCS11 token')
args = parser.parse_args() args = parser.parse_args()
try: try: