diff options
author | Simon Wilkinson <simon@sxw.org.uk> | 2014-02-09 16:09:48 +0000 |
---|---|---|
committer | Colin Watson <cjwatson@debian.org> | 2016-12-28 20:05:02 +0000 |
commit | 40ab38b3f501f3e21662f0294eef06789605c5f8 (patch) | |
tree | 739e0a31e245a718789908269c5af5807da13ef0 /monitor.c | |
parent | 971a7653746a6972b907dfe0ce139c06e4a6f482 (diff) |
GSSAPI key exchange support
This patch has been rejected upstream: "None of the OpenSSH developers are
in favour of adding this, and this situation has not changed for several
years. This is not a slight on Simon's patch, which is of fine quality, but
just that a) we don't trust GSSAPI implementations that much and b) we don't
like adding new KEX since they are pre-auth attack surface. This one is
particularly scary, since it requires hooks out to typically root-owned
system resources."
However, quite a lot of people rely on this in Debian, and it's better to
have it merged into the main openssh package rather than having separate
-krb5 packages (as we used to have). It seems to have a generally good
security history.
Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1242
Last-Updated: 2016-12-28
Patch-Name: gssapi.patch
Diffstat (limited to 'monitor.c')
-rw-r--r-- | monitor.c | 115 |
1 files changed, 106 insertions, 9 deletions
@@ -157,6 +157,8 @@ int mm_answer_gss_setup_ctx(int, Buffer *); | |||
157 | int mm_answer_gss_accept_ctx(int, Buffer *); | 157 | int mm_answer_gss_accept_ctx(int, Buffer *); |
158 | int mm_answer_gss_userok(int, Buffer *); | 158 | int mm_answer_gss_userok(int, Buffer *); |
159 | int mm_answer_gss_checkmic(int, Buffer *); | 159 | int mm_answer_gss_checkmic(int, Buffer *); |
160 | int mm_answer_gss_sign(int, Buffer *); | ||
161 | int mm_answer_gss_updatecreds(int, Buffer *); | ||
160 | #endif | 162 | #endif |
161 | 163 | ||
162 | #ifdef SSH_AUDIT_EVENTS | 164 | #ifdef SSH_AUDIT_EVENTS |
@@ -230,11 +232,18 @@ struct mon_table mon_dispatch_proto20[] = { | |||
230 | {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx}, | 232 | {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx}, |
231 | {MONITOR_REQ_GSSUSEROK, MON_ONCE|MON_AUTHDECIDE, mm_answer_gss_userok}, | 233 | {MONITOR_REQ_GSSUSEROK, MON_ONCE|MON_AUTHDECIDE, mm_answer_gss_userok}, |
232 | {MONITOR_REQ_GSSCHECKMIC, MON_ONCE, mm_answer_gss_checkmic}, | 234 | {MONITOR_REQ_GSSCHECKMIC, MON_ONCE, mm_answer_gss_checkmic}, |
235 | {MONITOR_REQ_GSSSIGN, MON_ONCE, mm_answer_gss_sign}, | ||
233 | #endif | 236 | #endif |
234 | {0, 0, NULL} | 237 | {0, 0, NULL} |
235 | }; | 238 | }; |
236 | 239 | ||
237 | struct mon_table mon_dispatch_postauth20[] = { | 240 | struct mon_table mon_dispatch_postauth20[] = { |
241 | #ifdef GSSAPI | ||
242 | {MONITOR_REQ_GSSSETUP, 0, mm_answer_gss_setup_ctx}, | ||
243 | {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx}, | ||
244 | {MONITOR_REQ_GSSSIGN, 0, mm_answer_gss_sign}, | ||
245 | {MONITOR_REQ_GSSUPCREDS, 0, mm_answer_gss_updatecreds}, | ||
246 | #endif | ||
238 | #ifdef WITH_OPENSSL | 247 | #ifdef WITH_OPENSSL |
239 | {MONITOR_REQ_MODULI, 0, mm_answer_moduli}, | 248 | {MONITOR_REQ_MODULI, 0, mm_answer_moduli}, |
240 | #endif | 249 | #endif |
@@ -301,6 +310,10 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor) | |||
301 | /* Permit requests for moduli and signatures */ | 310 | /* Permit requests for moduli and signatures */ |
302 | monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); | 311 | monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); |
303 | monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); | 312 | monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); |
313 | #ifdef GSSAPI | ||
314 | /* and for the GSSAPI key exchange */ | ||
315 | monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1); | ||
316 | #endif | ||
304 | 317 | ||
305 | /* The first few requests do not require asynchronous access */ | 318 | /* The first few requests do not require asynchronous access */ |
306 | while (!authenticated) { | 319 | while (!authenticated) { |
@@ -400,6 +413,10 @@ monitor_child_postauth(struct monitor *pmonitor) | |||
400 | monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); | 413 | monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); |
401 | monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); | 414 | monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); |
402 | monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); | 415 | monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); |
416 | #ifdef GSSAPI | ||
417 | /* and for the GSSAPI key exchange */ | ||
418 | monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1); | ||
419 | #endif | ||
403 | 420 | ||
404 | if (!no_pty_flag) { | 421 | if (!no_pty_flag) { |
405 | monitor_permit(mon_dispatch, MONITOR_REQ_PTY, 1); | 422 | monitor_permit(mon_dispatch, MONITOR_REQ_PTY, 1); |
@@ -1601,6 +1618,13 @@ monitor_apply_keystate(struct monitor *pmonitor) | |||
1601 | # endif | 1618 | # endif |
1602 | #endif /* WITH_OPENSSL */ | 1619 | #endif /* WITH_OPENSSL */ |
1603 | kex->kex[KEX_C25519_SHA256] = kexc25519_server; | 1620 | kex->kex[KEX_C25519_SHA256] = kexc25519_server; |
1621 | #ifdef GSSAPI | ||
1622 | if (options.gss_keyex) { | ||
1623 | kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server; | ||
1624 | kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server; | ||
1625 | kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server; | ||
1626 | } | ||
1627 | #endif | ||
1604 | kex->load_host_public_key=&get_hostkey_public_by_type; | 1628 | kex->load_host_public_key=&get_hostkey_public_by_type; |
1605 | kex->load_host_private_key=&get_hostkey_private_by_type; | 1629 | kex->load_host_private_key=&get_hostkey_private_by_type; |
1606 | kex->host_key_index=&get_hostkey_index; | 1630 | kex->host_key_index=&get_hostkey_index; |
@@ -1680,8 +1704,8 @@ mm_answer_gss_setup_ctx(int sock, Buffer *m) | |||
1680 | OM_uint32 major; | 1704 | OM_uint32 major; |
1681 | u_int len; | 1705 | u_int len; |
1682 | 1706 | ||
1683 | if (!options.gss_authentication) | 1707 | if (!options.gss_authentication && !options.gss_keyex) |
1684 | fatal("%s: GSSAPI authentication not enabled", __func__); | 1708 | fatal("%s: GSSAPI not enabled", __func__); |
1685 | 1709 | ||
1686 | goid.elements = buffer_get_string(m, &len); | 1710 | goid.elements = buffer_get_string(m, &len); |
1687 | goid.length = len; | 1711 | goid.length = len; |
@@ -1710,8 +1734,8 @@ mm_answer_gss_accept_ctx(int sock, Buffer *m) | |||
1710 | OM_uint32 flags = 0; /* GSI needs this */ | 1734 | OM_uint32 flags = 0; /* GSI needs this */ |
1711 | u_int len; | 1735 | u_int len; |
1712 | 1736 | ||
1713 | if (!options.gss_authentication) | 1737 | if (!options.gss_authentication && !options.gss_keyex) |
1714 | fatal("%s: GSSAPI authentication not enabled", __func__); | 1738 | fatal("%s: GSSAPI not enabled", __func__); |
1715 | 1739 | ||
1716 | in.value = buffer_get_string(m, &len); | 1740 | in.value = buffer_get_string(m, &len); |
1717 | in.length = len; | 1741 | in.length = len; |
@@ -1730,6 +1754,7 @@ mm_answer_gss_accept_ctx(int sock, Buffer *m) | |||
1730 | monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0); | 1754 | monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0); |
1731 | monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1); | 1755 | monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1); |
1732 | monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1); | 1756 | monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1); |
1757 | monitor_permit(mon_dispatch, MONITOR_REQ_GSSSIGN, 1); | ||
1733 | } | 1758 | } |
1734 | return (0); | 1759 | return (0); |
1735 | } | 1760 | } |
@@ -1741,8 +1766,8 @@ mm_answer_gss_checkmic(int sock, Buffer *m) | |||
1741 | OM_uint32 ret; | 1766 | OM_uint32 ret; |
1742 | u_int len; | 1767 | u_int len; |
1743 | 1768 | ||
1744 | if (!options.gss_authentication) | 1769 | if (!options.gss_authentication && !options.gss_keyex) |
1745 | fatal("%s: GSSAPI authentication not enabled", __func__); | 1770 | fatal("%s: GSSAPI not enabled", __func__); |
1746 | 1771 | ||
1747 | gssbuf.value = buffer_get_string(m, &len); | 1772 | gssbuf.value = buffer_get_string(m, &len); |
1748 | gssbuf.length = len; | 1773 | gssbuf.length = len; |
@@ -1770,10 +1795,11 @@ mm_answer_gss_userok(int sock, Buffer *m) | |||
1770 | { | 1795 | { |
1771 | int authenticated; | 1796 | int authenticated; |
1772 | 1797 | ||
1773 | if (!options.gss_authentication) | 1798 | if (!options.gss_authentication && !options.gss_keyex) |
1774 | fatal("%s: GSSAPI authentication not enabled", __func__); | 1799 | fatal("%s: GSSAPI not enabled", __func__); |
1775 | 1800 | ||
1776 | authenticated = authctxt->valid && ssh_gssapi_userok(authctxt->user); | 1801 | authenticated = authctxt->valid && |
1802 | ssh_gssapi_userok(authctxt->user, authctxt->pw); | ||
1777 | 1803 | ||
1778 | buffer_clear(m); | 1804 | buffer_clear(m); |
1779 | buffer_put_int(m, authenticated); | 1805 | buffer_put_int(m, authenticated); |
@@ -1786,5 +1812,76 @@ mm_answer_gss_userok(int sock, Buffer *m) | |||
1786 | /* Monitor loop will terminate if authenticated */ | 1812 | /* Monitor loop will terminate if authenticated */ |
1787 | return (authenticated); | 1813 | return (authenticated); |
1788 | } | 1814 | } |
1815 | |||
1816 | int | ||
1817 | mm_answer_gss_sign(int socket, Buffer *m) | ||
1818 | { | ||
1819 | gss_buffer_desc data; | ||
1820 | gss_buffer_desc hash = GSS_C_EMPTY_BUFFER; | ||
1821 | OM_uint32 major, minor; | ||
1822 | u_int len; | ||
1823 | |||
1824 | if (!options.gss_authentication && !options.gss_keyex) | ||
1825 | fatal("%s: GSSAPI not enabled", __func__); | ||
1826 | |||
1827 | data.value = buffer_get_string(m, &len); | ||
1828 | data.length = len; | ||
1829 | if (data.length != 20) | ||
1830 | fatal("%s: data length incorrect: %d", __func__, | ||
1831 | (int) data.length); | ||
1832 | |||
1833 | /* Save the session ID on the first time around */ | ||
1834 | if (session_id2_len == 0) { | ||
1835 | session_id2_len = data.length; | ||
1836 | session_id2 = xmalloc(session_id2_len); | ||
1837 | memcpy(session_id2, data.value, session_id2_len); | ||
1838 | } | ||
1839 | major = ssh_gssapi_sign(gsscontext, &data, &hash); | ||
1840 | |||
1841 | free(data.value); | ||
1842 | |||
1843 | buffer_clear(m); | ||
1844 | buffer_put_int(m, major); | ||
1845 | buffer_put_string(m, hash.value, hash.length); | ||
1846 | |||
1847 | mm_request_send(socket, MONITOR_ANS_GSSSIGN, m); | ||
1848 | |||
1849 | gss_release_buffer(&minor, &hash); | ||
1850 | |||
1851 | /* Turn on getpwnam permissions */ | ||
1852 | monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1); | ||
1853 | |||
1854 | /* And credential updating, for when rekeying */ | ||
1855 | monitor_permit(mon_dispatch, MONITOR_REQ_GSSUPCREDS, 1); | ||
1856 | |||
1857 | return (0); | ||
1858 | } | ||
1859 | |||
1860 | int | ||
1861 | mm_answer_gss_updatecreds(int socket, Buffer *m) { | ||
1862 | ssh_gssapi_ccache store; | ||
1863 | int ok; | ||
1864 | |||
1865 | if (!options.gss_authentication && !options.gss_keyex) | ||
1866 | fatal("%s: GSSAPI not enabled", __func__); | ||
1867 | |||
1868 | store.filename = buffer_get_string(m, NULL); | ||
1869 | store.envvar = buffer_get_string(m, NULL); | ||
1870 | store.envval = buffer_get_string(m, NULL); | ||
1871 | |||
1872 | ok = ssh_gssapi_update_creds(&store); | ||
1873 | |||
1874 | free(store.filename); | ||
1875 | free(store.envvar); | ||
1876 | free(store.envval); | ||
1877 | |||
1878 | buffer_clear(m); | ||
1879 | buffer_put_int(m, ok); | ||
1880 | |||
1881 | mm_request_send(socket, MONITOR_ANS_GSSUPCREDS, m); | ||
1882 | |||
1883 | return(0); | ||
1884 | } | ||
1885 | |||
1789 | #endif /* GSSAPI */ | 1886 | #endif /* GSSAPI */ |
1790 | 1887 | ||