diff options
author | Simon Wilkinson <simon@sxw.org.uk> | 2014-02-09 16:09:48 +0000 |
---|---|---|
committer | Colin Watson <cjwatson@debian.org> | 2018-10-20 22:54:00 +0100 |
commit | 72b1d308e6400194ef6e4e7dd45bfa48fa39b5e6 (patch) | |
tree | 2a3b57ae5446f4273804064ccc42659adfc2a3b2 /monitor.c | |
parent | 3d246f10429fc9a37b98eabef94fe8dc7c61002b (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: 2018-10-20
Patch-Name: gssapi.patch
Diffstat (limited to 'monitor.c')
-rw-r--r-- | monitor.c | 122 |
1 files changed, 113 insertions, 9 deletions
@@ -145,6 +145,8 @@ int mm_answer_gss_setup_ctx(int, struct sshbuf *); | |||
145 | int mm_answer_gss_accept_ctx(int, struct sshbuf *); | 145 | int mm_answer_gss_accept_ctx(int, struct sshbuf *); |
146 | int mm_answer_gss_userok(int, struct sshbuf *); | 146 | int mm_answer_gss_userok(int, struct sshbuf *); |
147 | int mm_answer_gss_checkmic(int, struct sshbuf *); | 147 | int mm_answer_gss_checkmic(int, struct sshbuf *); |
148 | int mm_answer_gss_sign(int, struct sshbuf *); | ||
149 | int mm_answer_gss_updatecreds(int, struct sshbuf *); | ||
148 | #endif | 150 | #endif |
149 | 151 | ||
150 | #ifdef SSH_AUDIT_EVENTS | 152 | #ifdef SSH_AUDIT_EVENTS |
@@ -215,11 +217,18 @@ struct mon_table mon_dispatch_proto20[] = { | |||
215 | {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx}, | 217 | {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx}, |
216 | {MONITOR_REQ_GSSUSEROK, MON_ONCE|MON_AUTHDECIDE, mm_answer_gss_userok}, | 218 | {MONITOR_REQ_GSSUSEROK, MON_ONCE|MON_AUTHDECIDE, mm_answer_gss_userok}, |
217 | {MONITOR_REQ_GSSCHECKMIC, MON_ONCE, mm_answer_gss_checkmic}, | 219 | {MONITOR_REQ_GSSCHECKMIC, MON_ONCE, mm_answer_gss_checkmic}, |
220 | {MONITOR_REQ_GSSSIGN, MON_ONCE, mm_answer_gss_sign}, | ||
218 | #endif | 221 | #endif |
219 | {0, 0, NULL} | 222 | {0, 0, NULL} |
220 | }; | 223 | }; |
221 | 224 | ||
222 | struct mon_table mon_dispatch_postauth20[] = { | 225 | struct mon_table mon_dispatch_postauth20[] = { |
226 | #ifdef GSSAPI | ||
227 | {MONITOR_REQ_GSSSETUP, 0, mm_answer_gss_setup_ctx}, | ||
228 | {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx}, | ||
229 | {MONITOR_REQ_GSSSIGN, 0, mm_answer_gss_sign}, | ||
230 | {MONITOR_REQ_GSSUPCREDS, 0, mm_answer_gss_updatecreds}, | ||
231 | #endif | ||
223 | #ifdef WITH_OPENSSL | 232 | #ifdef WITH_OPENSSL |
224 | {MONITOR_REQ_MODULI, 0, mm_answer_moduli}, | 233 | {MONITOR_REQ_MODULI, 0, mm_answer_moduli}, |
225 | #endif | 234 | #endif |
@@ -289,6 +298,10 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor) | |||
289 | /* Permit requests for moduli and signatures */ | 298 | /* Permit requests for moduli and signatures */ |
290 | monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); | 299 | monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); |
291 | monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); | 300 | monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); |
301 | #ifdef GSSAPI | ||
302 | /* and for the GSSAPI key exchange */ | ||
303 | monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1); | ||
304 | #endif | ||
292 | 305 | ||
293 | /* The first few requests do not require asynchronous access */ | 306 | /* The first few requests do not require asynchronous access */ |
294 | while (!authenticated) { | 307 | while (!authenticated) { |
@@ -401,6 +414,10 @@ monitor_child_postauth(struct monitor *pmonitor) | |||
401 | monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); | 414 | monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); |
402 | monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); | 415 | monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); |
403 | monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); | 416 | monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); |
417 | #ifdef GSSAPI | ||
418 | /* and for the GSSAPI key exchange */ | ||
419 | monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1); | ||
420 | #endif | ||
404 | 421 | ||
405 | if (auth_opts->permit_pty_flag) { | 422 | if (auth_opts->permit_pty_flag) { |
406 | monitor_permit(mon_dispatch, MONITOR_REQ_PTY, 1); | 423 | monitor_permit(mon_dispatch, MONITOR_REQ_PTY, 1); |
@@ -1666,6 +1683,13 @@ monitor_apply_keystate(struct monitor *pmonitor) | |||
1666 | # endif | 1683 | # endif |
1667 | #endif /* WITH_OPENSSL */ | 1684 | #endif /* WITH_OPENSSL */ |
1668 | kex->kex[KEX_C25519_SHA256] = kexc25519_server; | 1685 | kex->kex[KEX_C25519_SHA256] = kexc25519_server; |
1686 | #ifdef GSSAPI | ||
1687 | if (options.gss_keyex) { | ||
1688 | kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server; | ||
1689 | kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server; | ||
1690 | kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server; | ||
1691 | } | ||
1692 | #endif | ||
1669 | kex->load_host_public_key=&get_hostkey_public_by_type; | 1693 | kex->load_host_public_key=&get_hostkey_public_by_type; |
1670 | kex->load_host_private_key=&get_hostkey_private_by_type; | 1694 | kex->load_host_private_key=&get_hostkey_private_by_type; |
1671 | kex->host_key_index=&get_hostkey_index; | 1695 | kex->host_key_index=&get_hostkey_index; |
@@ -1756,8 +1780,8 @@ mm_answer_gss_setup_ctx(int sock, struct sshbuf *m) | |||
1756 | u_char *p; | 1780 | u_char *p; |
1757 | int r; | 1781 | int r; |
1758 | 1782 | ||
1759 | if (!options.gss_authentication) | 1783 | if (!options.gss_authentication && !options.gss_keyex) |
1760 | fatal("%s: GSSAPI authentication not enabled", __func__); | 1784 | fatal("%s: GSSAPI not enabled", __func__); |
1761 | 1785 | ||
1762 | if ((r = sshbuf_get_string(m, &p, &len)) != 0) | 1786 | if ((r = sshbuf_get_string(m, &p, &len)) != 0) |
1763 | fatal("%s: buffer error: %s", __func__, ssh_err(r)); | 1787 | fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
@@ -1789,8 +1813,8 @@ mm_answer_gss_accept_ctx(int sock, struct sshbuf *m) | |||
1789 | OM_uint32 flags = 0; /* GSI needs this */ | 1813 | OM_uint32 flags = 0; /* GSI needs this */ |
1790 | int r; | 1814 | int r; |
1791 | 1815 | ||
1792 | if (!options.gss_authentication) | 1816 | if (!options.gss_authentication && !options.gss_keyex) |
1793 | fatal("%s: GSSAPI authentication not enabled", __func__); | 1817 | fatal("%s: GSSAPI not enabled", __func__); |
1794 | 1818 | ||
1795 | if ((r = ssh_gssapi_get_buffer_desc(m, &in)) != 0) | 1819 | if ((r = ssh_gssapi_get_buffer_desc(m, &in)) != 0) |
1796 | fatal("%s: buffer error: %s", __func__, ssh_err(r)); | 1820 | fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
@@ -1810,6 +1834,7 @@ mm_answer_gss_accept_ctx(int sock, struct sshbuf *m) | |||
1810 | monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0); | 1834 | monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0); |
1811 | monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1); | 1835 | monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1); |
1812 | monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1); | 1836 | monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1); |
1837 | monitor_permit(mon_dispatch, MONITOR_REQ_GSSSIGN, 1); | ||
1813 | } | 1838 | } |
1814 | return (0); | 1839 | return (0); |
1815 | } | 1840 | } |
@@ -1821,8 +1846,8 @@ mm_answer_gss_checkmic(int sock, struct sshbuf *m) | |||
1821 | OM_uint32 ret; | 1846 | OM_uint32 ret; |
1822 | int r; | 1847 | int r; |
1823 | 1848 | ||
1824 | if (!options.gss_authentication) | 1849 | if (!options.gss_authentication && !options.gss_keyex) |
1825 | fatal("%s: GSSAPI authentication not enabled", __func__); | 1850 | fatal("%s: GSSAPI not enabled", __func__); |
1826 | 1851 | ||
1827 | if ((r = ssh_gssapi_get_buffer_desc(m, &gssbuf)) != 0 || | 1852 | if ((r = ssh_gssapi_get_buffer_desc(m, &gssbuf)) != 0 || |
1828 | (r = ssh_gssapi_get_buffer_desc(m, &mic)) != 0) | 1853 | (r = ssh_gssapi_get_buffer_desc(m, &mic)) != 0) |
@@ -1851,10 +1876,11 @@ mm_answer_gss_userok(int sock, struct sshbuf *m) | |||
1851 | int r, authenticated; | 1876 | int r, authenticated; |
1852 | const char *displayname; | 1877 | const char *displayname; |
1853 | 1878 | ||
1854 | if (!options.gss_authentication) | 1879 | if (!options.gss_authentication && !options.gss_keyex) |
1855 | fatal("%s: GSSAPI authentication not enabled", __func__); | 1880 | fatal("%s: GSSAPI not enabled", __func__); |
1856 | 1881 | ||
1857 | authenticated = authctxt->valid && ssh_gssapi_userok(authctxt->user); | 1882 | authenticated = authctxt->valid && |
1883 | ssh_gssapi_userok(authctxt->user, authctxt->pw); | ||
1858 | 1884 | ||
1859 | sshbuf_reset(m); | 1885 | sshbuf_reset(m); |
1860 | if ((r = sshbuf_put_u32(m, authenticated)) != 0) | 1886 | if ((r = sshbuf_put_u32(m, authenticated)) != 0) |
@@ -1871,5 +1897,83 @@ mm_answer_gss_userok(int sock, struct sshbuf *m) | |||
1871 | /* Monitor loop will terminate if authenticated */ | 1897 | /* Monitor loop will terminate if authenticated */ |
1872 | return (authenticated); | 1898 | return (authenticated); |
1873 | } | 1899 | } |
1900 | |||
1901 | int | ||
1902 | mm_answer_gss_sign(int socket, struct sshbuf *m) | ||
1903 | { | ||
1904 | gss_buffer_desc data; | ||
1905 | gss_buffer_desc hash = GSS_C_EMPTY_BUFFER; | ||
1906 | OM_uint32 major, minor; | ||
1907 | size_t len; | ||
1908 | u_char *p; | ||
1909 | int r; | ||
1910 | |||
1911 | if (!options.gss_authentication && !options.gss_keyex) | ||
1912 | fatal("%s: GSSAPI not enabled", __func__); | ||
1913 | |||
1914 | if ((r = sshbuf_get_string(m, &p, &len)) != 0) | ||
1915 | fatal("%s: buffer error: %s", __func__, ssh_err(r)); | ||
1916 | data.value = p; | ||
1917 | data.length = len; | ||
1918 | if (data.length != 20) | ||
1919 | fatal("%s: data length incorrect: %d", __func__, | ||
1920 | (int) data.length); | ||
1921 | |||
1922 | /* Save the session ID on the first time around */ | ||
1923 | if (session_id2_len == 0) { | ||
1924 | session_id2_len = data.length; | ||
1925 | session_id2 = xmalloc(session_id2_len); | ||
1926 | memcpy(session_id2, data.value, session_id2_len); | ||
1927 | } | ||
1928 | major = ssh_gssapi_sign(gsscontext, &data, &hash); | ||
1929 | |||
1930 | free(data.value); | ||
1931 | |||
1932 | sshbuf_reset(m); | ||
1933 | if ((r = sshbuf_put_u32(m, major)) != 0 || | ||
1934 | (r = sshbuf_put_string(m, hash.value, hash.length)) != 0) | ||
1935 | fatal("%s: buffer error: %s", __func__, ssh_err(r)); | ||
1936 | |||
1937 | mm_request_send(socket, MONITOR_ANS_GSSSIGN, m); | ||
1938 | |||
1939 | gss_release_buffer(&minor, &hash); | ||
1940 | |||
1941 | /* Turn on getpwnam permissions */ | ||
1942 | monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1); | ||
1943 | |||
1944 | /* And credential updating, for when rekeying */ | ||
1945 | monitor_permit(mon_dispatch, MONITOR_REQ_GSSUPCREDS, 1); | ||
1946 | |||
1947 | return (0); | ||
1948 | } | ||
1949 | |||
1950 | int | ||
1951 | mm_answer_gss_updatecreds(int socket, struct sshbuf *m) { | ||
1952 | ssh_gssapi_ccache store; | ||
1953 | int r, ok; | ||
1954 | |||
1955 | if (!options.gss_authentication && !options.gss_keyex) | ||
1956 | fatal("%s: GSSAPI not enabled", __func__); | ||
1957 | |||
1958 | if ((r = sshbuf_get_cstring(m, &store.filename, NULL)) != 0 || | ||
1959 | (r = sshbuf_get_cstring(m, &store.envvar, NULL)) != 0 || | ||
1960 | (r = sshbuf_get_cstring(m, &store.envval, NULL)) != 0) | ||
1961 | fatal("%s: buffer error: %s", __func__, ssh_err(r)); | ||
1962 | |||
1963 | ok = ssh_gssapi_update_creds(&store); | ||
1964 | |||
1965 | free(store.filename); | ||
1966 | free(store.envvar); | ||
1967 | free(store.envval); | ||
1968 | |||
1969 | sshbuf_reset(m); | ||
1970 | if ((r = sshbuf_put_u32(m, ok)) != 0) | ||
1971 | fatal("%s: buffer error: %s", __func__, ssh_err(r)); | ||
1972 | |||
1973 | mm_request_send(socket, MONITOR_ANS_GSSUPCREDS, m); | ||
1974 | |||
1975 | return(0); | ||
1976 | } | ||
1977 | |||
1874 | #endif /* GSSAPI */ | 1978 | #endif /* GSSAPI */ |
1875 | 1979 | ||