/*
SSSD
Helper child to commmunicate with SmartCard via NSS
Authors:
Sumit Bose <sbose@redhat.com>
Copyright (C) 2015 Red Hat
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <popt.h>
#include <nss.h>
#include <base64.h>
#include <cryptohi.h>
#include <secmod.h>
#include <cert.h>
#include <keyhi.h>
#include <pk11pub.h>
#include <prerror.h>
#include <ocsp.h>
#include "util/child_common.h"
#include "util/crypto/sss_crypto.h"
enum op_mode {
};
enum pin_mode {
};
{
/* give up if 1) no password was supplied, or 2) the password has already
* been rejected once by this token. */
return NULL;
}
}
{
"PK11_GetLowLevelKeyIDForCert failed [%d][%s].\n",
return NULL;
}
if (key_id_str == NULL) {
return NULL;
}
return key_id_str;
}
struct cert_verify_opts *cert_verify_opts,
const char *module_name_in, const char *token_name_in,
{
int ret;
const char *slot_name;
const char *token_name;
const char *module_name;
const char *label;
return EIO;
}
}
}
}
NULL);
return EIO;
}
"Description [%s] Manufacturer [%s] flags [%lu].\n",
break;
}
}
return EIO;
}
if (PK11_IsFriendly(slot)) {
} else {
"Token is NOT friendly.\n");
if (mode == OP_PREAUTH) {
if (rv != SECSuccess) {
"PK11_UpdateSlotAttribute failed, continue.\n");
}
}
}
/* TODO: check PK11_ProtectedAuthenticationPath() and return the result */
if (rv != SECSuccess) {
return EIO;
}
} else {
"Login required but no PIN available, continue.\n");
}
} else {
}
return EIO;
}
if (cert_list_node->cert) {
} else {
}
}
return EIO;
}
if (cert_verify_opts->do_ocsp) {
if (rv != SECSuccess) {
"CERT_EnableOCSPChecking failed: [%d][%s].\n",
return EIO;
}
if (rv != SECSuccess) {
"CERT_SetOCSPDefaultResponder failed: [%d][%s].\n",
return EIO;
}
if (rv != SECSuccess) {
"CERT_EnableOCSPDefaultResponder failed: [%d][%s].\n",
return EIO;
}
}
}
found_cert = NULL;
if (valid_certs == NULL) {
goto done;
}
continue;
}
"found cert[%s][%s]\n",
if (cert_verify_opts->do_verification) {
NULL, &returned_usage);
"Certificate [%s][%s] not valid [%d][%s], skipping.\n",
continue;
}
}
key_id_str = NULL;
}
/* Check if we found the certificates we needed for authentication or
* the requested ones for pre-auth. For authentication all attributes
* must be given and match, for pre-auth only the given ones must
* match. */
&& module_name_in != NULL
&& token_name_in != NULL
&& key_id_str != NULL
|| (mode == OP_PREAUTH
&& (module_name_in == NULL
|| (module_name_in != NULL
&& (token_name_in == NULL
|| (token_name_in != NULL
if (rv != SECSuccess) {
"CERT_AddCertToListTail failed [%d][%s].\n",
goto done;
}
}
}
/* Disable OCSP default responder so that NSS can shutdown properly */
if (cert_verify_opts->do_ocsp
if (rv != SECSuccess) {
"CERT_DisableOCSPDefaultResponder failed: [%d][%s].\n",
}
}
if (CERT_LIST_EMPTY(valid_certs)) {
goto done;
}
"More than one certificate found for authentication, "
"aborting!\n");
goto done;
}
if (found_cert == NULL) {
"No certificate found for authentication, aborting!\n");
goto done;
}
if (rv != SECSuccess) {
"PK11_GenerateRandom failed [%d][%s].\n",
return EIO;
}
"PK11_FindPrivateKeyFromCert failed [%d][%s]."
"Maybe PIN is missing.\n",
goto done;
}
if (algtag == SEC_OID_UNKNOWN) {
"SEC_GetSignatureAlgorithmOidTag failed [%d][%s].\n",
goto done;
}
random_value, sizeof(random_value),
if (rv != SECSuccess) {
goto done;
}
"CERT_ExtractPublicKey failed [%d][%s].\n",
goto done;
}
NULL);
if (rv != SECSuccess) {
goto done;
}
"Certificate verified and validated.\n");
}
goto done;
}
if (key_id_str == NULL) {
goto done;
}
/* The NSS nickname is typically token_name:label, so the label starts
* after the ':'. */
} else {
label++;
}
} else {
label = "- no label found -";
}
goto done;
}
}
done:
}
if (valid_certs != NULL) {
/* The certificates can be found in valid_certs and cert_list and
* CERT_DestroyCertList() will free the certificates as well. To avoid
* a double free the nodes from valid_certs are removed first because
* valid_certs will only have a sub-set of the certificates. */
}
}
}
if (rv != SECSuccess) {
}
return ret;
}
{
char *str;
errno = 0;
if (len == -1) {
return ret;
}
return EINVAL;
}
return ENOMEM;
}
"Input contains additional data, only PIN expected.\n");
return EINVAL;
}
return EOK;
}
{
int opt;
_("Debug level"), NULL},
_("Add debug timestamps"), NULL},
_("Show timestamps with microseconds"), NULL},
_("An open file descriptor for the debug logs"), NULL},
&debug_to_stderr, 0,
_("Send the debug output to stderr directly."), NULL },
NULL},
NULL},
NULL},
_("Module name for authentication"), NULL},
_("Token name for authentication"), NULL},
_("Key ID for authentication"), NULL},
};
/* Set debug level to invalid value so we can decide if -d 0 was used. */
/*
* This child can run as root or as sssd user relying on policy kit to
* grant access to pcscd. This means that no setuid or setgid bit must be
* set on the binary. We still should make sure to run with a restrictive
* umask but do not have to make additional precautions like clearing the
* environment. This would allow to use e.g. pkcs11-spy.so for further
* debugging.
*/
switch(opt) {
case 'a':
"\n--auth and --pre are mutually exclusive and " \
"should be only used once.\n\n");
_exit(-1);
}
break;
case 'p':
"\n--auth and --pre are mutually exclusive and " \
"should be only used once.\n\n");
_exit(-1);
}
mode = OP_PREAUTH;
break;
case 'i':
"and should be only used once.\n\n");
_exit(-1);
}
break;
case 'k':
"and should be only used once.\n\n");
_exit(-1);
}
break;
default:
_exit(-1);
}
}
_exit(-1);
}
"either --auth or --pre must be specified.\n\n");
_exit(-1);
"either --pin or --keypad must be specified.\n");
_exit(-1);
}
if (debug_prg_name == NULL) {
goto fail;
}
if (debug_fd != -1) {
}
}
goto fail;
}
"--module_name, --token_name and --key_id must be given for "
"authentication");
goto fail;
}
goto fail;
}
goto fail;
}
}
goto fail;
}
}
return EXIT_SUCCESS;
fail:
return EXIT_FAILURE;
}