On Fri, Jul 17, 2015 at 09:01:49PM +0200, Sumit Bose wrote:
On Fri, Jul 10, 2015 at 06:40:30PM +0200, Sumit Bose wrote:
> Hi,
>
> this is the initial version of my patch which add Smartcard
> authentication to SSSD. I'm still working on a design page which will
> explain everything in more details so I will only add a short version
> here.
>
> The main job will be done by a new child process called p11_child. Since
> the Smartcard support in GDM is based on NSS I used NSS for the first
> version of p11_child as well. But since all PKCS#11 (API to talk to
> Smartcards) related code is in this child process adding support for
> other PKCS#11 frameworks like p11-kit would be straight forward (in fact
> I already started on the p11-kit version). Using NSS here means you have
> to add the PKCS#11 module for your Smartcards reader to /etc/pki/nssdb
> (the NSS DB GDM uses as well) with modutil or pk11install from the
> coolkey package.
>
> The PAM configuration so far must not be changed. pam_sss will do a
> pre-auth request similar to the OPT case for find a suitable
> authentication method for the user. The pam responder then checks is
> Smartcard authentication is enabled (pam_cert_auth = True in the [pam]
> section of sssd.conf), if the service is a local one and if there if a
> valid certificate can be found which is available in the users LDAP
> entry as well. If all this checks pass pam_sss will ask the user for a
> PIN and then SSSD tries to validate that PIN, public and private keys
> all relate to each other. If no Smartcard is found for the user the
> standard password prompt is displayed.
>
> With some valuable input form Christian Heimes I think I found a way to
> test the Smartcard support even without real hardware but I still have
> to work out some of the details. I will add instructions to the design
> page and better and more unit tests.
>
> Any comments and suggestions are welcome.
Please find attached an improved version of the patches. Especially
there are improvements to the test, the return values from the p11_child
are not mocked used the actual retrieved certificate data. The test data
causes some increase in the patch size. I plan to replace this with data
which is generate during the test run but for a start it is easier this
way.
I also added a 7th patch which should resolve
https://fedorahosted.org/sssd/ticket/2711 (SSH with certificates).
Strictly it is not related to Smartcard authentication via PAM but it
depends on the NSS version of the cert utilities (patch 0001) so I
included it here as well.
On the design page I added the 'How to test' section
https://fedorahosted.org/sssd/wiki/DesignDocs/SmartcardAuthenticationStep...
which hopefully gives sufficient details how to set up a test
environment.
bye,
Sumit
From b73cab487ffc4704239d4b5f5b63a75b43602e6b Mon Sep 17 00:00:00
2001
From: Sumit Bose <sbose(a)redhat.com>
Date: Fri, 26 Jun 2015 17:55:23 +0200
Subject: [PATCH 4/7] authok: add support for Smart Card related authtokens
---
src/sss_client/sss_cli.h | 7 ++++
src/tests/cmocka/test_authtok.c | 75 +++++++++++++++++++++++++++++++++++++++++
src/util/authtok.c | 64 +++++++++++++++++++++++++++++++++++
src/util/authtok.h | 41 ++++++++++++++++++++++
Only one typo in doxygen comments:
--- a/src/util/authtok.h
+++ b/src/util/authtok.h
@@ -223,4 +223,45 @@ errno_t sss_authtok_set_2fa(struct sss_auth_token *tok,
errno_t sss_authtok_get_2fa(struct sss_auth_token *tok,
const char **fa1, size_t *fa1_len,
const char **fa2, size_t *fa2_len);
+
+/**
+ * @brief Set a Smart Card pin into a an auth token, replacing any previous data
+ *
+ * @param tok A pointer to a sss_auth_token structure to change, also
+ * used as a memory context to allocate the internal data.
+ * @param pin A string
+ * @param len The length of the string or, if 0 is passed,
+ * then strlen(password) will be used internally.
+ *
+ * @return EOK on success
+ * ENOMEM on error
+ */
+errno_t sss_authtok_set_sc_pin(struct sss_auth_token *tok, const char *pin,
+ size_t len);
+
+/**
+ * @brief Returns a Smart Card pin as const string if the auth token is of
+ * type SSS_AUTHTOK_TYPE_SC_PIN, otherwise it returns an error
+ *
+ * @param tok A pointer to an sss_auth_token
+ * @param pwd A pointer to a const char *, that will point to a null
~~~
should be pin
+ * terminated string
+ * @param len The length of the pin string
+ *
+ * @return EOK on success
+ * ENOENT if the token is empty
+ * EACCESS if the token is not a Smart Card pin token
+ */
+errno_t sss_authtok_get_sc_pin(struct sss_auth_token *tok, const char **pin,
+ size_t *len);
+
+/**
+ * @brief Sets an auth token to type SSS_AUTHTOK_TYPE_SC_KEYPAD, replacing any
+ * previous data
+ *
+ * @param tok A pointer to a sss_auth_token structure to change, also
+ * used as a memory context to allocate the internal data.
+ */
+void sss_authtok_set_sc_keypad(struct sss_auth_token *tok);
+
#endif /* __AUTHTOK_H__ */
--
2.1.0
From 25897f8c5b421cb765bbfa6c47933e904e66bf06 Mon Sep 17 00:00:00
2001
From: Sumit Bose <sbose(a)redhat.com>
Date: Fri, 10 Jul 2015 17:54:07 +0200
Subject: [PATCH 5/7] PAM: add certificate support to PAM (pre-)auth requests
---
Makefile.am | 5 +
configure.ac | 3 +
contrib/sssd.spec.in | 1 +
src/confdb/confdb.h | 2 +
src/responder/pam/pamsrv.c | 34 +++
src/responder/pam/pamsrv.h | 26 ++
src/responder/pam/pamsrv_cmd.c | 321 ++++++++++++++++++++---
src/responder/pam/pamsrv_p11.c | 508 ++++++++++++++++++++++++++++++++++++
src/sss_client/sss_cli.h | 1 +
src/tests/cmocka/p11_nssdb/cert9.db | Bin 0 -> 13312 bytes
src/tests/cmocka/p11_nssdb/key4.db | Bin 0 -> 14336 bytes
src/tests/cmocka/test_pam_srv.c | 508 +++++++++++++++++++++++++++++++++++-
src/util/util_errors.c | 1 +
src/util/util_errors.h | 1 +
14 files changed, 1372 insertions(+), 39 deletions(-)
create mode 100644 src/responder/pam/pamsrv_p11.c
create mode 100644 src/tests/cmocka/p11_nssdb/cert9.db
create mode 100644 src/tests/cmocka/p11_nssdb/key4.db
[...]
diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in
index a68f1bdec917cb4af6b4fd31860e642c69ada4de..898d5c5b2d5668387586c1c42fc8d382cc6bf0c3
100644
--- a/contrib/sssd.spec.in
+++ b/contrib/sssd.spec.in
@@ -689,6 +689,7 @@ rm -rf $RPM_BUILD_ROOT
%{_libexecdir}/%{servicename}/sssd_autofs
%{_libexecdir}/%{servicename}/sssd_ssh
%{_libexecdir}/%{servicename}/sssd_sudo
+%{_libexecdir}/%{servicename}/p11_child
As said earlier, this hunk belongs to an earlier patch. Also, in
Makefile.am, the permissions on p11_child are root.sssd 04750, don't we
need to do the same here?
%dir %{_libdir}/%{name}
%{_libdir}/%{name}/libsss_simple.so
diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
[...]
diff --git a/src/responder/pam/pamsrv_p11.c
b/src/responder/pam/pamsrv_p11.c
new file mode 100644
index 0000000000000000000000000000000000000000..bf404958340d4d155a0b60c4deda87fa26e1ad25
--- /dev/null
+++ b/src/responder/pam/pamsrv_p11.c
@@ -0,0 +1,508 @@
+/*
+ SSSD
+
+ PAM Responder - certificate realted requests
+
+ Copyright (C) Sumit Bose <sbose(a)redhat.com> 2015
+
+ This program is free software; you can redistribute it and/or modify
+ 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 <time.h>
+
+#include "util/util.h"
+#include "providers/data_provider.h"
+#include "util/child_common.h"
+#include "util/strtonum.h"
+#include "responder/pam/pamsrv.h"
+
+
+#ifndef SSSD_LIBEXEC_PATH
+#error "SSSD_LIBEXEC_PATH not defined"
+#endif /* SSSD_LIBEXEC_PATH */
+
+#define P11_CHILD_LOG_FILE "p11_child"
+#define P11_CHILD_PATH SSSD_LIBEXEC_PATH"/p11_child"
+
+#define DEFAULT_NSS_DB "/etc/pki/nssdb"
We already have CONFDB_DEFAULT_SSH_CA_DB, do we need both default?
+
+errno_t p11_child_init(struct pam_ctx *pctx)
+{
+ return child_debug_init(P11_CHILD_LOG_FILE, &pctx->p11_child_debug_fd);
+}
+
[...]
+errno_t pam_check_cert_recv(struct tevent_req *req, TALLOC_CTX
*mem_ctx,
+ uint8_t **buf, ssize_t *buf_len)
+{
+ struct pam_check_cert_state *state =
+ tevent_req_data(req, struct pam_check_cert_state);
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ if (buf_len != NULL) {
+ *buf_len = state->len;
+ }
+
+ if (buf != NULL) {
+ *buf = talloc_steal(mem_ctx, state->buf);
+ }
+
+ return EOK;
+}
+
+errno_t parse_p11_child_response(TALLOC_CTX *mem_ctx, uint8_t *buf,
+ ssize_t buf_len, char **_cert,
+ char **_token_name)
Since this function only makes sense to parse output of
pam_check_cert_recv what do you think of merging this function into
pam_check_cert request and making the request return cert and token name
directly?
+{
+ int ret;
+ TALLOC_CTX *tmp_ctx = NULL;
+ uint8_t *p;
+ uint8_t *pn;
+ char *endptr;
+ size_t count = 0;
+ char *cert = NULL;
+ char *str;
+ char *token_name = NULL;
+ size_t c;
+
+ if (buf_len < 0) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Error occured while reading data from p11_child.\n");
+ return EIO;
+ }
+
+ if (buf_len == 0) {
+ DEBUG(SSSDBG_TRACE_LIBS, "No certificate found.\n");
+ ret = EOK;
+ goto done;
+ }
+
+ p = memchr(buf, '\n', buf_len);
+ if (p == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "Missing new-line in p11_child
response.\n");
+ return EINVAL;
+ }
+ if (p == buf) {
+ DEBUG(SSSDBG_OP_FAILURE, "Missing counter in p11_child response.\n");
+ return EINVAL;
+ }
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
+ return ENOMEM;
+ }
+
+ token_name = talloc_strndup(tmp_ctx, (char*) buf, (p - buf));
+ if (token_name == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n");
+ return ENOMEM;
we should goto done here to get rid of tmp_ctx
+ }
+
+ p++;
+ pn = memchr(p, '\n', buf_len - (p - buf));
+ if (pn == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Missing new-line in p11_child response.\n");
+ ret = EINVAL;
+ goto done;
+ }
+
+ if (pn == p) {
+ DEBUG(SSSDBG_OP_FAILURE, "Missing cert in p11_child response.\n");
+ ret = EINVAL;
+ goto done;
+ }
+
+ cert = talloc_strndup(tmp_ctx, (char *) p, (pn - p));
+ if(cert == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+ DEBUG(SSSDBG_TRACE_ALL, "Found cert [%s].\n", cert);
+
+ ret = EOK;
+
+done:
+ if (ret == EOK) {
+ *_token_name = talloc_steal(mem_ctx, token_name);
+ *_cert = talloc_steal(mem_ctx, cert);
+ }
+
+ talloc_free(tmp_ctx);
+
+ return ret;
+}
From 7d505b88cd615db4e5318d01327794e3f81b7e4c Mon Sep 17 00:00:00
2001
From: Sumit Bose <sbose(a)redhat.com>
Date: Fri, 3 Jul 2015 14:05:11 +0200
Subject: [PATCH 6/7] pam_sss: add sc support
ACK
From f6d366ebd1307dfd36a907e55f32a66caf2b0f9d Mon Sep 17 00:00:00
2001
From: Sumit Bose <sbose(a)redhat.com>
Date: Wed, 15 Jul 2015 09:40:00 +0200
Subject: [PATCH 7/7] ssh: generate public keys from certificate
Resolves:
https://fedorahosted.org/sssd/ticket/2711
---
src/confdb/confdb.h | 2 +
src/config/SSSDConfig/__init__.py.in | 1 +
src/config/etc/sssd.api.conf | 1 +
src/man/sssd.conf.5.xml | 13 ++++
src/responder/ssh/sshsrv.c | 9 +++
src/responder/ssh/sshsrv_cmd.c | 54 ++++++++++++---
src/responder/ssh/sshsrv_private.h | 1 +
src/tests/cmocka/test_cert_utils.c | 60 +++++++++++++++++
src/util/cert.h | 4 ++
src/util/cert/nss/cert.c | 125 +++++++++++++++++++++++++++++++++++
10 files changed, 259 insertions(+), 11 deletions(-)
diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
index 254246a4c26c3cdb0b57ab987a53ebddea771218..2d7832e40fd0c9ad1ea94b86dd257fc87186d39a
100644
--- a/src/confdb/confdb.h
+++ b/src/confdb/confdb.h
@@ -135,6 +135,8 @@
#define CONFDB_DEFAULT_SSH_HASH_KNOWN_HOSTS true
#define CONFDB_SSH_KNOWN_HOSTS_TIMEOUT "ssh_known_hosts_timeout"
#define CONFDB_DEFAULT_SSH_KNOWN_HOSTS_TIMEOUT 180
+#define CONFDB_SSH_CA_DB "ca_db"
+#define CONFDB_DEFAULT_SSH_CA_DB "/etc/pki/nssdb"
I wonder if we should use sysconfigdir here, because the default paths
if you use configure will be /usr/etc/
But I know this is a bit academic on modern systems..
[...]
--- a/src/responder/ssh/sshsrv_cmd.c
+++ b/src/responder/ssh/sshsrv_cmd.c
@@ -27,6 +27,7 @@
#include "util/util.h"
#include "util/crypto/sss_crypto.h"
#include "util/sss_ssh.h"
+#include "util/cert.h"
#include "db/sysdb.h"
#include "db/sysdb_ssh.h"
#include "providers/data_provider.h"
@@ -219,7 +220,8 @@ static errno_t
ssh_user_pubkeys_search_next(struct ssh_cmd_ctx *cmd_ctx)
{
errno_t ret;
- const char *attrs[] = { SYSDB_NAME, SYSDB_SSH_PUBKEY, NULL };
+ const char *attrs[] = { SYSDB_NAME, SYSDB_SSH_PUBKEY, SYSDB_USER_CERT,
+ NULL };
struct ldb_result *res;
DEBUG(SSSDBG_TRACE_FUNC,
@@ -794,6 +796,8 @@ ssh_cmd_parse_request(struct ssh_cmd_ctx *cmd_ctx)
static errno_t decode_and_add_base64_data(struct ssh_cmd_ctx *cmd_ctx,
struct ldb_message_element *el,
+ bool cert_data,
Do we anticipate any more formats? If yes, then let's add an enum here,
otherwise the bool is fine.
+ struct ssh_ctx *ssh_ctx,
size_t fqname_len,
const char *fqname,
size_t *c)