Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial pkinit support #137

Closed
wants to merge 10 commits into from

Conversation

sumit-bose
Copy link
Contributor

This series of patches add initial support for PKINIT
(https://fedorahosted.org/sssd/ticket/3270) by forwarding the information about
the selected certificate from the Smartcard to the backends. Currently only
the krb5 backend supports Smartcard authentication the other backends will
return an error code which will tell the PAM responder to fall back to local
Smartcard authentication as it is currently the case.

Testing requires a working PKINIT setup which e.g. can be done with AD by
setting up a CA and generating certificates as described in
https://fedorahosted.org/sssd/wiki/DesignDocs/SmartcardAuthenticationTestingWithAD.

But currently more important is regression testing, i.e. making sure all other
authentication methods are still working as expected.

@jhrozek jhrozek self-assigned this Feb 6, 2017
@jhrozek
Copy link
Contributor

jhrozek commented Feb 6, 2017

There are some Coverity warnings:

Error: UNINIT (CWE-457):
sssd-1.15.1/src/p11_child/p11_child_nss.c:112: var_decl: Declaring variable "key_id_str" without initializer.
sssd-1.15.1/src/p11_child/p11_child_nss.c:482: uninit_use_in_call: Using uninitialized value "key_id_str" when calling "PORT_Free".
#  480|   
#  481|       SECITEM_FreeItem(key_id, PR_TRUE);
#  482|->     PORT_Free(key_id_str);
#  483|   
#  484|       PORT_Free(signed_random_value.data);

Error: COMPILER_WARNING:
sssd-1.15.1/src/p11_child/p11_child_nss.c: scope_hint: In function 'do_work'
sssd-1.15.1/src/p11_child/p11_child_nss.c:482:5: warning: 'key_id_str' may be used uninitialized in this function [-Wmaybe-uninitialized]
#     PORT_Free(key_id_str);
#     ^
#  480|   
#  481|       SECITEM_FreeItem(key_id, PR_TRUE);
#  482|->     PORT_Free(key_id_str);
#  483|   
#  484|       PORT_Free(signed_random_value.data);

Error: NEGATIVE_RETURNS (CWE-394):
sssd-1.15.1/src/providers/krb5/krb5_child.c:1836: negative_return_fn: Function "get_and_save_tgt(kr, newpassword)" returns a negative number.
sssd-1.15.1/src/providers/krb5/krb5_child.c:1484:9: return_negative_constant: Explicitly returning negative value "-1765328324".
sssd-1.15.1/src/providers/krb5/krb5_child.c:1836: var_assign: Assigning: signed variable "kerr" = "get_and_save_tgt".
sssd-1.15.1/src/providers/krb5/krb5_child.c:1844: negative_returns: "kerr" is passed to a parameter that cannot be negative.
sssd-1.15.1/src/providers/krb5/krb5_child.c:1603:9: neg_sink_parm_call: Passing "kerr" to "sss_strerror", which cannot accept a negative number.
sssd-1.15.1/src/util/util_errors.c:117:5: neg_sink_parm_call: Passing "error" to "strerror", which cannot accept a negative number.
# 1842|           kerr = k5c_attach_ccname_msg(kr);
# 1843|       }
# 1844|->     return map_krb5_error(kerr);
# 1845|   }
# 1846|   

Error: NEGATIVE_RETURNS (CWE-394):
sssd-1.15.1/src/providers/krb5/krb5_child.c:1878: negative_return_fn: Function "get_and_save_tgt(kr, password)" returns a negative number.
sssd-1.15.1/src/providers/krb5/krb5_child.c:1484:9: return_negative_constant: Explicitly returning negative value "-1765328324".
sssd-1.15.1/src/providers/krb5/krb5_child.c:1878: var_assign: Assigning: signed variable "kerr" = "get_and_save_tgt".
sssd-1.15.1/src/providers/krb5/krb5_child.c:1913: negative_returns: "kerr" is passed to a parameter that cannot be negative.
sssd-1.15.1/src/providers/krb5/krb5_child.c:1603:9: neg_sink_parm_call: Passing "kerr" to "sss_strerror", which cannot accept a negative number.
sssd-1.15.1/src/util/util_errors.c:117:5: neg_sink_parm_call: Passing "error" to "strerror", which cannot accept a negative number.
# 1911|               }
# 1912|           }
# 1913|->         ret = map_krb5_error(kerr);
# 1914|           goto done;
# 1915|       }

Error: UNUSED_VALUE (CWE-563):
sssd-1.15.1/src/responder/pam/pamsrv_cmd.c:1505: value_overwrite: Overwriting previous write to "ret" with value from "pam_check_user_search(preq)".
sssd-1.15.1/src/responder/pam/pamsrv_cmd.c:1507: value_overwrite: Overwriting previous write to "ret" with value "0".
sssd-1.15.1/src/responder/pam/pamsrv_cmd.c:1488: returned_value: Assigning value from "sss_parse_name_for_domains(preq->pd, preq->cctx->rctx->domains, preq->cctx->rctx->default_domain, cert_user, &preq->pd->domain, &preq->pd->user)" to "ret" here, but that stored value is overwritten before it can be used.
# 1486|                                       cert_user);
# 1487|   
# 1488|->             ret = sss_parse_name_for_domains(preq->pd,
# 1489|                                                preq->cctx->rctx->domains,
# 1490|                                                preq->cctx->rctx->default_domain,

Error: UNINIT (CWE-457):
sssd-1.15.1/src/util/authtok.c:597: var_decl: Declaring variable "key_id_len" without initializer.
sssd-1.15.1/src/util/authtok.c:665: uninit_use: Using uninitialized value "key_id_len".
#  663|       }
#  664|   
#  665|->     if (key_id_len != 0) {
#  666|           *key_id = talloc_strndup(mem_ctx,
#  667|                                         (const char *) blob + c + pin_len

Error: COMPILER_WARNING:
sssd-1.15.1/src/util/authtok.c: scope_hint: In function 'sss_auth_unpack_sc_blob'
sssd-1.15.1/src/util/authtok.c:666:19: warning: 'key_id_len' may be used uninitialized in this function [-Wmaybe-uninitialized]
#         *key_id = talloc_strndup(mem_ctx,
#                   ^
#  664|   
#  665|       if (key_id_len != 0) {
#  666|->         *key_id = talloc_strndup(mem_ctx,
#  667|                                         (const char *) blob + c + pin_len
#  668|                                                                 + token_name_len

@jhrozek
Copy link
Contributor

jhrozek commented Feb 6, 2017

pam_srv_test doesn't like being run under valgrind:
http://sssd-ci.duckdns.org/logs/job/61/71/rhel7/ci-build-debug/ci-make-check-valgrind.log

@sumit-bose
Copy link
Contributor Author

Thank you for running the tests, the valgirind issue was the same as the last coverity warning.

@lslebodn
Copy link
Contributor

lslebodn commented Feb 10, 2017 via email

@sumit-bose
Copy link
Contributor Author

Hi Lukas,

thank you for your comments. I move get_pkinit_identity() out if the ifdef block. For pam_check_user_done() I removed the assignment which should hopefully silence the Coverity warning. Since we use pam_check_user_done() without assigning the return code to a variable at other places as well I hope you agree with this. I think we can even make pam_check_user_done() to return void but this should be handled by a different patch.

bye,
Sumit

@jhrozek
Copy link
Contributor

jhrozek commented Feb 20, 2017

There is a small issue where sss_authtok_set_sc is used before it's defined, which would break bisect.

btw I'm battling a bit with the downstream tests, it looks like saying these patches break renewals wasn't right, because there is some issue with tests that makes the renewal downstream tests fail even with the current master. So I'm re-running the tests more or less one by one and inspecting the debug messages to see if we have more failures with the patches than with master. I'm also running some totally manual tests..

I will post more issues (if I see any) here, but in the meantime, I spotted only the function-used-before-defined one.

@jhrozek
Copy link
Contributor

jhrozek commented Feb 20, 2017

OK, apart from the issue with the patch compilation, I found one more with manual testing -- it looks like changing the expired password of a newly created IPA user is not working correctly. I'm getting:


(Mon Feb 20 20:54:03 2017) [[sssd[krb5_child[1798]]]] [sss_child_krb5_trace_cb] (0x4000): [1798] 1487624043.229515: Received error from KDC: -1765328361/Password has expired

(Mon Feb 20 20:54:03 2017) [[sssd[krb5_child[1798]]]] [get_and_save_tgt] (0x0020): 1526: [-1765328361][Password has expired]
(Mon Feb 20 20:54:03 2017) [[sssd[krb5_child[1798]]]] [map_krb5_error] (0x0020): [1432158285][No authentication methode available].
(Mon Feb 20 20:54:03 2017) [[sssd[krb5_child[1798]]]] [k5c_send_data] (0x0200): Received error code 1432158285
(Mon Feb 20 20:54:03 2017) [[sssd[krb5_child[1798]]]] [pack_response_packet] (0x2000): response packet size: [4]
(Mon Feb 20 20:54:03 2017) [[sssd[krb5_child[1798]]]] [k5c_send_data] (0x4000): Response sent.
(Mon Feb 20 20:54:03 2017) [[sssd[krb5_child[1798]]]] [main] (0x0400): krb5_child completed successfully
(Mon Feb 20 20:54:03 2017) [sssd[be[ipa.test]]] [read_pipe_handler] (0x0400): EOF received, client finished
(Mon Feb 20 20:54:03 2017) [sssd[be[ipa.test]]] [check_wait_queue] (0x1000): Wait queue for user [authtest2@ipa.test] is empty.
(Mon Feb 20 20:54:03 2017) [sssd[be[ipa.test]]] [krb5_auth_queue_done] (0x1000): krb5_auth_queue request [0x19ccf00] done.
(Mon Feb 20 20:54:03 2017) [sssd[be[ipa.test]]] [dp_req_done] (0x0400): DP Request [PAM Authenticate #8]: Request handler finished [0]: Success
(Mon Feb 20 20:54:03 2017) [sssd[be[ipa.test]]] [_dp_req_recv] (0x0400): DP Request [PAM Authenticate #8]: Receiving request data.
(Mon Feb 20 20:54:03 2017) [sssd[be[ipa.test]]] [dp_req_destructor] (0x0400): DP Request [PAM Authenticate #8]: Request removed.
(Mon Feb 20 20:54:03 2017) [sssd[be[ipa.test]]] [dp_req_destructor] (0x0400): Number of active DP request: 0
(Mon Feb 20 20:54:03 2017) [sssd[be[ipa.test]]] [dp_pam_reply] (0x1000): DP Request [PAM Authenticate #8]: Sending result [18][ipa.test]

This works fine with the current master. Apart from that, I ran downstream tests for AD, LDAP/LDAP and LDAP/KRB5.

Manual testing included:

  • IPA auth with a password, online and offline
  • IPA auth with OTP, online and offline
  • AD auth, AD auth with a UPN
  • subdomain auth
  • IPA password change

The code looks mostly good, I will make another pass on it tomorrow, but I suppose if I even ask for anything, it would be comments or so.

@sumit-bose
Copy link
Contributor Author

Thank you for review and testing. I fixed the issue with changing the expired password and reordered the patches so that sss_authtok_set_sc is defined before it is used.


/* A missing pin is ok in the case of a reader with a keyboard */
if (pin == NULL) {
pin = "";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it would be nice to set the pin_len to strlen(pin) here to avoid issues if someone passed in NULL pin but non-zero pin_len. Same with other input strings.

&needed_size);
if (ret != EOK) {
D(("sss_auth_pack_sc_blob failed."));
ret = PAM_BUF_ERR;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks like pi->pam_authtok is not freed here


if (pi->pam_authtok == NULL) {
ret = PAM_BUF_ERR;
goto done;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this block looks like it belongs before sss_auth_pack_sc_blob and after malloc

@jhrozek
Copy link
Contributor

jhrozek commented Feb 22, 2017

The patches work now, if the three small issues above and the individual compilation are addressed, I'll ack

Since there can be multiple rounds trips between the PAM client and SSSD
it might be possible that the same data is send multiple times by SSSD.
So before overriding the old data it should be freed. I've seen this
with the domain name which is send both in the pre-auth and the auth
responses. To be on the safe side I added free() for some other items as
well.
ERR_SC_AUTH_NOT_SUPPORTED can be used by backends to indicate that
Smartcard authentication is not supported. ERR_NO_AUTH_METHOD_AVAILABLE
can be used by backends that no authentication method was found.
The blobs contains beside the PIN the name of the PKCS#11 module and the
token name where the certificate of the user was found and the key id.
Those data will be used e.g. by the pkinit module to make sure them
right certificate is used.
@sumit-bose
Copy link
Contributor Author

Thank you for the rigid review, I've fixed the comments move some strucht members to a previous patch to not break the individual compilation.

@jhrozek
Copy link
Contributor

jhrozek commented Feb 23, 2017 via email

@jhrozek
Copy link
Contributor

jhrozek commented Feb 23, 2017

@jhrozek jhrozek closed this Feb 23, 2017
@jhrozek jhrozek added Pushed and removed Accepted labels Feb 23, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants