From 2162171ad517501ba511fa9f8191945d01857bb4 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Tue, 22 Jan 2019 12:00:50 +0000 Subject: upstream: Support keys that set the CKA_ALWAYS_AUTHENTICATE by requring a fresh login after the C_SignInit operation. based on patch from Jakub Jelen in bz#2638; ok markus OpenBSD-Commit-ID: a76e66996ba7c0923b46b74d46d499b811786661 --- ssh-pkcs11.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 95 insertions(+), 26 deletions(-) (limited to 'ssh-pkcs11.c') diff --git a/ssh-pkcs11.c b/ssh-pkcs11.c index 036ee811..384ac1ed 100644 --- a/ssh-pkcs11.c +++ b/ssh-pkcs11.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-pkcs11.c,v 1.39 2019/01/21 02:05:38 djm Exp $ */ +/* $OpenBSD: ssh-pkcs11.c,v 1.40 2019/01/22 12:00:50 djm Exp $ */ /* * Copyright (c) 2010 Markus Friedl. All rights reserved. * Copyright (c) 2014 Pedro Martelletto. All rights reserved. @@ -239,6 +239,85 @@ pkcs11_find(struct pkcs11_provider *p, CK_ULONG slotidx, CK_ATTRIBUTE *attr, return (ret); } +static int +pkcs11_login(struct pkcs11_key *k11, CK_USER_TYPE type) +{ + struct pkcs11_slotinfo *si; + CK_FUNCTION_LIST *f; + char *pin = NULL, prompt[1024]; + CK_RV rv; + + if (!k11->provider || !k11->provider->valid) { + error("no pkcs11 (valid) provider found"); + return (-1); + } + + f = k11->provider->function_list; + si = &k11->provider->slotinfo[k11->slotidx]; + + if (!pkcs11_interactive) { + error("need pin entry%s", + (si->token.flags & CKF_PROTECTED_AUTHENTICATION_PATH) ? + " on reader keypad" : ""); + return (-1); + } + if (si->token.flags & CKF_PROTECTED_AUTHENTICATION_PATH) + verbose("Deferring PIN entry to reader keypad."); + else { + snprintf(prompt, sizeof(prompt), "Enter PIN for '%s': ", + si->token.label); + if ((pin = read_passphrase(prompt, RP_ALLOW_EOF)) == NULL) { + debug("%s: no pin specified", __func__); + return (-1); /* bail out */ + } + } + rv = f->C_Login(si->session, type, (u_char *)pin, + (pin != NULL) ? strlen(pin) : 0); + if (pin != NULL) + freezero(pin, strlen(pin)); + if (rv != CKR_OK && rv != CKR_USER_ALREADY_LOGGED_IN) { + error("C_Login failed: %lu", rv); + return (-1); + } + si->logged_in = 1; + return (0); +} + +static int +pkcs11_check_obj_bool_attrib(struct pkcs11_key *k11, CK_OBJECT_HANDLE obj, + CK_ATTRIBUTE_TYPE type, int *val) +{ + struct pkcs11_slotinfo *si; + CK_FUNCTION_LIST *f; + CK_BBOOL flag = 0; + CK_ATTRIBUTE attr; + CK_RV rv; + + *val = 0; + + if (!k11->provider || !k11->provider->valid) { + error("no pkcs11 (valid) provider found"); + return (-1); + } + + f = k11->provider->function_list; + si = &k11->provider->slotinfo[k11->slotidx]; + + attr.type = type; + attr.pValue = &flag; + attr.ulValueLen = sizeof(flag); + + rv = f->C_GetAttributeValue(si->session, obj, &attr, 1); + if (rv != CKR_OK) { + error("C_GetAttributeValue failed: %lu", rv); + return (-1); + } + *val = flag != 0; + debug("%s: provider %p slot %lu object %lu: attrib %lu = %d", + __func__, k11->provider, k11->slotidx, obj, type, *val); + return (0); +} + static int pkcs11_get_key(struct pkcs11_key *k11, CK_MECHANISM_TYPE mech_type) { @@ -250,7 +329,8 @@ pkcs11_get_key(struct pkcs11_key *k11, CK_MECHANISM_TYPE mech_type) CK_BBOOL true_val; CK_MECHANISM mech; CK_ATTRIBUTE key_filter[3]; - char *pin = NULL, prompt[1024]; + int always_auth = 0; + int did_login = 0; if (!k11->provider || !k11->provider->valid) { error("no pkcs11 (valid) provider found"); @@ -261,32 +341,11 @@ pkcs11_get_key(struct pkcs11_key *k11, CK_MECHANISM_TYPE mech_type) si = &k11->provider->slotinfo[k11->slotidx]; if ((si->token.flags & CKF_LOGIN_REQUIRED) && !si->logged_in) { - if (!pkcs11_interactive) { - error("need pin entry%s", (si->token.flags & - CKF_PROTECTED_AUTHENTICATION_PATH) ? - " on reader keypad" : ""); - return (-1); - } - if (si->token.flags & CKF_PROTECTED_AUTHENTICATION_PATH) - verbose("Deferring PIN entry to reader keypad."); - else { - snprintf(prompt, sizeof(prompt), - "Enter PIN for '%s': ", si->token.label); - pin = read_passphrase(prompt, RP_ALLOW_EOF); - if (pin == NULL) - return (-1); /* bail out */ - } - rv = f->C_Login(si->session, CKU_USER, (u_char *)pin, - (pin != NULL) ? strlen(pin) : 0); - if (pin != NULL) { - explicit_bzero(pin, strlen(pin)); - free(pin); - } - if (rv != CKR_OK && rv != CKR_USER_ALREADY_LOGGED_IN) { - error("C_Login failed: %lu", rv); + if (pkcs11_login(k11, CKU_USER) < 0) { + error("login failed"); return (-1); } - si->logged_in = 1; + did_login = 1; } memset(&key_filter, 0, sizeof(key_filter)); @@ -321,6 +380,16 @@ pkcs11_get_key(struct pkcs11_key *k11, CK_MECHANISM_TYPE mech_type) return (-1); } + pkcs11_check_obj_bool_attrib(k11, obj, CKA_ALWAYS_AUTHENTICATE, + &always_auth); /* ignore errors here */ + if (always_auth && !did_login) { + debug("%s: always-auth key", __func__); + if (pkcs11_login(k11, CKU_CONTEXT_SPECIFIC) < 0) { + error("login failed for always-auth key"); + return (-1); + } + } + return (0); } -- cgit v1.2.1