diff --git a/README.md b/README.md index ee94cc9..ce35bd6 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,10 @@ To sign using a PIV-II smartcard such as the Yubikey, install `pkcs11-tool` from marginaltool -e pkcs11 -i 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 -i bc-digsign://sign?… + The script will prompt for the PIN to unlock the smartcard. To find the key ID, run pkcs11-tool -O diff --git a/marginaltool b/marginaltool index d62aea9..d92f0c9 100755 --- a/marginaltool +++ b/marginaltool @@ -43,7 +43,10 @@ def init(args): args.id = config.get(args.url, 'id', fallback=None) if not args.id: 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 import tkinter.simpledialog # only needed for PIN entry @@ -58,7 +61,7 @@ def sign(b64data, args): if not args.keyfile: raise Exception('keyfile not specified') cmd = ['openssl', 'pkeyutl', '-sign', '-inkey', args.keyfile, '-pkeyopt', 'digest:sha256'] - env = None + env = {} data = base64.b64decode(b64data) case 'pkcs11': @@ -72,14 +75,14 @@ def sign(b64data, args): 'SHA-384': '3041300d060960864801650304020205000430', '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} data = bytes.fromhex(digest_info['SHA-256']) + base64.b64decode(b64data) case '_': 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: 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('-k', '--keyfile', type=pathlib.Path, help='key file') parser.add_argument('-c', '--certfile', type=pathlib.Path, help='certificate file') - parser.add_argument('-i', '--id', type=int, metavar='', 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='', help='key ID on PKCS11 token') args = parser.parse_args() try: