Skip to content

Commit

Permalink
Merge pull request #210 from olcf/cleanup-yubi-for-release
Browse files Browse the repository at this point in the history
Cleanup yubi for release
  • Loading branch information
carljbai authored Aug 14, 2023
2 parents 3162a20 + 22ae40d commit 3a7ed06
Show file tree
Hide file tree
Showing 11 changed files with 48 additions and 19 deletions.
8 changes: 8 additions & 0 deletions libpkpass/commands/arguments.py
Original file line number Diff line number Diff line change
Expand Up @@ -272,4 +272,12 @@
"help": "SC backend to use: opensc or yubi",
},
},
"PKCS11_module_path": {
"args": ["--PKCS11-module-path"],
"kwargs": {
"type": str,
"default": "/usr/local/lib/libykcs11.dylib",
"help": "Path to yubi PKCS11 module",
},
},
}
1 change: 1 addition & 0 deletions libpkpass/commands/clip.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ def _run_command_execution(self):
passphrase=self.passphrase,
card_slot=self.args["card_slot"],
SCBackend=self.args["SCBackend"],
PKCS11_module_path=self.args["PKCS11_module_path"],
)
if not self.args["noverify"]:
result = password.verify_entry(
Expand Down
2 changes: 2 additions & 0 deletions libpkpass/commands/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ def update_pass(self, pass_value):
escrow_users=self.args["escrow_users"],
minimum=self.args["min_escrow"],
SCBackend=self.args["SCBackend"],
PKCS11_module_path=self.args["PKCS11_module_path"],
)
pass_entry["recipients"][self.args["identity"]] = swap_pass["recipients"][
self.args["identity"]
Expand Down Expand Up @@ -199,6 +200,7 @@ def create_pass(self, password1, description, authorizer, recipient_list=None):
escrow_users=self.args["escrow_users"],
minimum=self.args["min_escrow"],
SCBackend=self.args["SCBackend"],
PKCS11_module_path=self.args["PKCS11_module_path"],
)

password.write_password_data(
Expand Down
2 changes: 2 additions & 0 deletions libpkpass/commands/distribute.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ def _run_command_execution(self):
passphrase=self.passphrase,
card_slot=self.args["card_slot"],
SCBackend=self.args["SCBackend"],
PKCS11_module_path=self.args["PKCS11_module_path"],
)
password.add_recipients(
secret=plaintext_pw,
Expand All @@ -62,6 +63,7 @@ def _run_command_execution(self):
escrow_users=self.args["escrow_users"],
minimum=self.args["min_escrow"],
SCBackend=self.args["SCBackend"],
PKCS11_module_path=self.args["PKCS11_module_path"],
)

password.write_password_data(dist_pass)
Expand Down
1 change: 1 addition & 0 deletions libpkpass/commands/export.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ def _iterate_pdb(self, passworddb, crypt_pass=False):
passphrase=self.passphrase,
card_slot=self.args["card_slot"],
SCBackend=self.args["SCBackend"],
PKCS11_module_path=self.args["PKCS11_module_path"],
)
password.recipients[uid]["encrypted_secret"] = plaintext_pw.encode("UTF-8")
password.write_password_data(
Expand Down
1 change: 1 addition & 0 deletions libpkpass/commands/populate.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ def _decrypt_password_entry(self, password):
passphrase=self.passphrase,
card_slot=self.args["card_slot"],
SCBackend=self.args["SCBackend"],
PKCS11_module_path=self.args["PKCS11_module_path"],
)
distributor = password.recipients[self.iddb.id["name"]]["distributor"]
if not self.args["noverify"]:
Expand Down
1 change: 1 addition & 0 deletions libpkpass/commands/rename.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ def _run_command_execution(self):
passphrase=self.passphrase,
card_slot=self.args["card_slot"],
SCBackend=self.args["SCBackend"],
PKCS11_module_path=self.args["PKCS11_module_path"],
)
self._confirmation(plaintext_pw)
else:
Expand Down
2 changes: 2 additions & 0 deletions libpkpass/commands/show.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ def _behalf_prep(self, password):
passphrase=self.passphrase,
card_slot=self.args["card_slot"],
SCBackend=self.args["SCBackend"],
PKCS11_module_path=self.args["PKCS11_module_path"],
)
with open(temp_key, "w", encoding="ASCII") as fname:
fname.write(
Expand Down Expand Up @@ -156,6 +157,7 @@ def _decrypt_password_entry(self, password, distributor):
passphrase=self.passphrase,
card_slot=self.args["card_slot"],
SCBackend=self.args["SCBackend"],
PKCS11_module_path=self.args["PKCS11_module_path"],
)
dist_obj = (
self.iddb.session.query(Recipient)
Expand Down
23 changes: 10 additions & 13 deletions libpkpass/crypto.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
SignatureCreationError,
X509CertificateError,
BadBackendError,
PKPassError,
)


Expand Down Expand Up @@ -96,9 +97,8 @@ def print_card_info(card_slot, identity, verbosity, color, theme_map, SCBackend)
for out in out_list:
stripped = out.decode("UTF-8").strip()
if "Yubico" not in stripped:
print("unsupported SC type")
# todo: better handling
exit(1)
# exit(1)
raise PKPassError("Unsupported SC type for backend yubi.\nYubico not in:\n" + stripped)
if int(stripped.split('CCID')[1] or 0) == int(card_slot):
verbosity = verbosity + 1 if verbosity < 2 else 2
stripped = "Using Slot" + ("\n").join(stripped.split("\n")[:verbosity])
Expand All @@ -120,7 +120,7 @@ def print_all_slots(slot_info, color, theme_map):


def pk_decrypt_string(
ciphertext_string, ciphertext_derived_key, identity, passphrase, SCBackend="opensc", card_slot=None
ciphertext_string, ciphertext_derived_key, identity, passphrase, SCBackend="opensc", card_slot=None, PKCS11_module_path="/usr/local/lib/libykcs11.dylib"
):
####################################################################
"""Decrypt a base64 encoded string for the provided identity"""
Expand Down Expand Up @@ -161,7 +161,7 @@ def pk_decrypt_string(
raise DecryptionError(stdout) from err
returncode = proc.returncode
elif SCBackend == "yubi":
# todo: fix this
# todo: this can be improved to not use temp files
# https://developers.yubico.com/yubico-piv-tool/YKCS11/Supported_applications/openssl_engine.html
with NamedTemporaryFile(delete=False) as fname:
fname.write(urlsafe_b64decode(ciphertext_derived_key))
Expand All @@ -175,8 +175,7 @@ def pk_decrypt_string(
"-pkeyopt", "rsa_padding_mode:pkcs1",
"-in", fname.name
]
# todo: make path an option
with Popen(command, stdout=PIPE, stdin=PIPE, stderr=STDOUT, env=dict(environ, PKCS11_MODULE_PATH="/usr/local/lib/libykcs11.dylib")) as proc:
with Popen(command, stdout=PIPE, stdin=PIPE, stderr=STDOUT, env=dict(environ, PKCS11_MODULE_PATH=PKCS11_module_path)) as proc:
stdout, _ = proc.communicate(
input=urlsafe_b64decode(ciphertext_derived_key)
)
Expand All @@ -198,7 +197,7 @@ def pk_decrypt_string(
)


def pk_sign_string(string, identity, passphrase, SCBackend="opensc", card_slot=None):
def pk_sign_string(string, identity, passphrase, SCBackend="opensc", card_slot=None, PKCS11_module_path="/usr/local/lib/libykcs11.dylib"):
####################################################################
"""Compute the hash of string and create a digital signature"""
####################################################################
Expand Down Expand Up @@ -237,7 +236,7 @@ def pk_sign_string(string, identity, passphrase, SCBackend="opensc", card_slot=N
with open(out.name, "rb") as sigfile:
signature = urlsafe_b64encode(handle_python_strings(sigfile.read()))
elif SCBackend == "yubi":
# todo: fix this
# todo: this can be improved to not use temp files
# https://developers.yubico.com/yubico-piv-tool/YKCS11/Supported_applications/openssl_engine.html
with NamedTemporaryFile(delete=False) as fname:
fname.write(stringhash.encode("UTF-8"))
Expand All @@ -253,8 +252,7 @@ def pk_sign_string(string, identity, passphrase, SCBackend="opensc", card_slot=N
"-in", fname.name,
"-out", out.name
]
# todo: make this an option
with Popen(command, stdout=PIPE, stdin=PIPE, stderr=STDOUT, env=dict(environ, PKCS11_MODULE_PATH="/usr/local/lib/libykcs11.dylib")) as proc:
with Popen(command, stdout=PIPE, stdin=PIPE, stderr=STDOUT, env=dict(environ, PKCS11_MODULE_PATH=PKCS11_module_path)) as proc:
stdout, _ = proc.communicate(
input=stringhash.encode("UTF-8")
)
Expand Down Expand Up @@ -442,7 +440,7 @@ def get_card_subjecthash(SCBackend, card_slot=None):

def get_card_serial(card_slot=None):
####################################################################
"""Return the serial element of a card"""
"""Return the serial element of a yubico card"""
####################################################################
command = ["yubico-piv-tool", "-a", "status"]
if card_slot is not None and card_slot != 0:
Expand All @@ -454,7 +452,6 @@ def get_card_serial(card_slot=None):
for line in stdout.decode("utf-8").strip().lower().splitlines():
if "serial number:" in line:
return line.split(":")[1].replace(" ", "").replace("\t", "")
# todo: fix this
raise X509CertificateError("Smartcard not detected")
return None

Expand Down
25 changes: 19 additions & 6 deletions libpkpass/password.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ def process_escrow_map(
escrow_users=None,
minimum=None,
SCBackend="opensc",
PKCS11_module_path="/usr/local/lib/libykcs11.dylib",
):
####################################################################
"""Process the escrow user map into escrow users"""
Expand All @@ -104,6 +105,7 @@ def process_escrow_map(
passphrase,
card_slot,
SCBackend,
PKCS11_module_path,
)
i += 1

Expand All @@ -125,6 +127,7 @@ def add_recipients(
escrow_users=None,
minimum=None,
SCBackend="opensc",
PKCS11_module_path="/usr/local/lib/libykcs11.dylib",
):
####################################################################
"""Add recipients to the recipient list of this password object"""
Expand All @@ -142,6 +145,7 @@ def add_recipients(
passphrase=passphrase,
card_slot=card_slot,
SCBackend=SCBackend,
PKCS11_module_path=PKCS11_module_path,
)
for r in tqdm(recipients, leave=False)
}
Expand Down Expand Up @@ -171,6 +175,7 @@ def add_recipients(
escrow_users=escrow_users,
minimum=minimum,
SCBackend=SCBackend,
PKCS11_module_path=PKCS11_module_path,
)
except ValueError as err:
print(f"Warning cannot create escrow shares, reason: {err}")
Expand Down Expand Up @@ -220,6 +225,7 @@ def _add_recipient(
passphrase=None,
card_slot=None,
SCBackend="opensc",
PKCS11_module_path="/usr/local/lib/libykcs11.dylib",
):
####################################################################
"""Add recipient or sharer to list"""
Expand All @@ -242,6 +248,7 @@ def _add_recipient(
passphrase,
SCBackend,
card_slot,
PKCS11_module_path,
)

return recipient_entry
Expand All @@ -250,7 +257,7 @@ def _add_recipient(
f"Identity '{recipient}' is not on the recipient list for password '{self.metadata['name']}'"
) from err

def decrypt_entry(self, identity=None, passphrase=None, card_slot=None, SCBackend=None):
def decrypt_entry(self, identity=None, passphrase=None, card_slot=None, SCBackend=None, PKCS11_module_path="/usr/local/lib/libykcs11.dylib"):
####################################################################
"""Decrypt this password entry for a particular identity
(usually the user)"""
Expand All @@ -271,6 +278,7 @@ def decrypt_entry(self, identity=None, passphrase=None, card_slot=None, SCBacken
passphrase,
SCBackend,
card_slot,
PKCS11_module_path,
)
except KeyError:
try:
Expand All @@ -283,6 +291,8 @@ def decrypt_entry(self, identity=None, passphrase=None, card_slot=None, SCBacken
identity,
passphrase,
SCBackend,
card_slot,
PKCS11_module_path,
)
else:
cert_key = get_card_fingerprint(SCBackend, card_slot=card_slot)
Expand All @@ -295,9 +305,10 @@ def decrypt_entry(self, identity=None, passphrase=None, card_slot=None, SCBacken
passphrase,
SCBackend,
card_slot,
PKCS11_module_path,
)
except DecryptionError as err:
msg = create_error_message(recipient_entry["timestamp"], card_slot, SCBackend)
msg = create_error_message(recipient_entry["timestamp"], card_slot, SCBackend, err)
raise DecryptionError(
f"Error decrypting password named '{self.metadata['name']}'. {msg}"
) from err
Expand All @@ -306,7 +317,7 @@ def decrypt_entry(self, identity=None, passphrase=None, card_slot=None, SCBacken
f"Error decrypting password named '{self.metadata['name']}'. Appropriate private key not found"
) from err
except DecryptionError as err:
msg = create_error_message(recipient_entry["timestamp"], card_slot, SCBackend)
msg = create_error_message(recipient_entry["timestamp"], card_slot, SCBackend, err)
raise DecryptionError(
f"Error decrypting password named '{self.metadata['name']}'. {msg}"
) from err
Expand Down Expand Up @@ -402,16 +413,18 @@ def write_password_data(
raise PasswordIOError(f"Error creating '{filename}'") from error


def create_error_message(recipient_timestamp, card_slot, SCBackend="opensc"):
def create_error_message(recipient_timestamp, card_slot, SCBackend="opensc", err=None):
card_start = get_card_startdate(SCBackend)
card_start = datetime.timestamp(parser.parse(card_start))
distribute_time = float(recipient_timestamp)
# Slots are indexed at 0 so when enumerating you add 1
# There is also an additional information line so add 1 again
if int(card_slot) + 2 > len(get_card_info(SCBackend)[0]):
# For opensc there is also an additional information line so add 1 again
if (int(card_slot) + 2 > len(get_card_info(SCBackend)[0]) and SCBackend == "opensc") or (int(card_slot) + 1 > len(get_card_info(SCBackend)[0]) and SCBackend == "yubi"):
msg = "Attempting to use card slot that is not connected"
elif distribute_time < card_start:
msg = "Password distributed before this certificate was created"
elif err is not None and "dlopen" in str(err.msg):
msg = "Perhaps a bad path in PKCS11_module_path"
else:
msg = "Perhaps a bad pin/passphrase?"
return msg
1 change: 1 addition & 0 deletions libpkpass/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ def collect_args(parsedargs):
"color": True,
"verbosity": 0,
"SCBackend": "opensc",
"PKCS11_module_path": "/usr/local/lib/libykcs11.dylib",
}
cli_args = parsedargs if isinstance(parsedargs, dict) else vars(parsedargs)
config_args = get_config_args(cli_args["config"], cli_args)
Expand Down

0 comments on commit 3a7ed06

Please sign in to comment.