static SSL_SESSION *generate_dtls_session(struct openconnect_info *vpninfo, int dtlsver, const SSL_CIPHER *cipher) { struct oc_text_buf *buf = buf_alloc(); SSL_SESSION *dtls_session; const unsigned char *asn; uint16_t cid; buf_append_bytes(buf, "\x30\x80", 2); // SEQUENCE, indeterminate length buf_append_INTEGER(buf, 1 /* SSL_SESSION_ASN1_VERSION */); buf_append_INTEGER(buf, dtlsver); store_be16(&cid, SSL_CIPHER_get_id(cipher) & 0xffff); buf_append_OCTET_STRING(buf, &cid, 2); buf_append_OCTET_STRING(buf, vpninfo->dtls_session_id, sizeof(vpninfo->dtls_session_id)); buf_append_OCTET_STRING(buf, vpninfo->dtls_secret, sizeof(vpninfo->dtls_secret)); /* If the length actually fits in one byte (which it should), do * it that way. Else, leave it indeterminate and add two * end-of-contents octets to mark the end of the SEQUENCE. */ if (!buf_error(buf) && buf->pos <= 0x80) buf->data[1] = buf->pos - 2; else buf_append_bytes(buf, "\0\0", 2); if (buf_error(buf)) { vpn_progress(vpninfo, PRG_ERR, _("Failed to create SSL_SESSION ASN.1 for OpenSSL: %s\n"), strerror(buf_error(buf))); buf_free(buf); return NULL; } asn = (void *)buf->data; dtls_session = d2i_SSL_SESSION(NULL, &asn, buf->pos); buf_free(buf); if (!dtls_session) { vpn_progress(vpninfo, PRG_ERR, _("OpenSSL failed to parse SSL_SESSION ASN.1\n")); openconnect_report_ssl_errors(vpninfo); return NULL; } return dtls_session; }
int socks_gssapi_auth(struct openconnect_info *vpninfo) { gss_buffer_desc in = GSS_C_EMPTY_BUFFER; gss_buffer_desc out = GSS_C_EMPTY_BUFFER; gss_OID mech = GSS_C_NO_OID; OM_uint32 major, minor; unsigned char *pktbuf; int i; int ret = -EIO; if (gssapi_setup(vpninfo, "rcmd", 1)) return -EIO; pktbuf = malloc(65538); if (!pktbuf) return -ENOMEM; while (1) { major = gss_init_sec_context(&minor, GSS_C_NO_CREDENTIAL, &vpninfo->gss_context[1], vpninfo->gss_target_name[1], (gss_OID)&gss_mech_spnego, GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_DELEG_FLAG | GSS_C_SEQUENCE_FLAG, GSS_C_INDEFINITE, GSS_C_NO_CHANNEL_BINDINGS, &in, &mech, &out, NULL, NULL); in.value = NULL; if (major == GSS_S_COMPLETE) { /* If we still have a token to send, send it. */ if (!out.length) { vpn_progress(vpninfo, PRG_DEBUG, _("GSSAPI authentication completed\n")); gss_release_buffer(&minor, &out); ret = 0; break; } } else if (major != GSS_S_CONTINUE_NEEDED) { print_gss_err(vpninfo, "gss_init_sec_context()", mech, major, minor); break; } if (out.length > 65535) { vpn_progress(vpninfo, PRG_ERR, _("GSSAPI token too large (%zd bytes)\n"), out.length); break; } pktbuf[0] = 1; /* ver */ pktbuf[1] = 1; /* mtyp */ store_be16(pktbuf + 2, out.length); memcpy(pktbuf + 4, out.value, out.length); free(out.value); vpn_progress(vpninfo, PRG_TRACE, _("Sending GSSAPI token of %zu bytes\n"), out.length + 4); i = vpninfo->ssl_write(vpninfo, (void *)pktbuf, out.length + 4); if (i < 0) { vpn_progress(vpninfo, PRG_ERR, _("Failed to send GSSAPI authentication token to proxy: %s\n"), strerror(-i)); break; } i = vpninfo->ssl_read(vpninfo, (void *)pktbuf, 4); if (i < 0) { vpn_progress(vpninfo, PRG_ERR, _("Failed to receive GSSAPI authentication token from proxy: %s\n"), strerror(-i)); break; } if (pktbuf[1] == 0xff) { vpn_progress(vpninfo, PRG_ERR, _("SOCKS server reported GSSAPI context failure\n")); break; } else if (pktbuf[1] != 1) { vpn_progress(vpninfo, PRG_ERR, _("Unknown GSSAPI status response (0x%02x) from SOCKS server\n"), pktbuf[1]); break; } in.length = load_be16(pktbuf + 2); in.value = pktbuf; if (!in.length) { vpn_progress(vpninfo, PRG_DEBUG, _("GSSAPI authentication completed\n")); ret = 0; break; } i = vpninfo->ssl_read(vpninfo, (void *)pktbuf, in.length); if (i < 0) { vpn_progress(vpninfo, PRG_ERR, _("Failed to receive GSSAPI authentication token from proxy: %s\n"), strerror(-i)); break; } vpn_progress(vpninfo, PRG_TRACE, _("Got GSSAPI token of %zu bytes: %02x %02x %02x %02x\n"), in.length, pktbuf[0], pktbuf[1], pktbuf[2], pktbuf[3]); } if (!ret) { ret = -EIO; pktbuf[0] = 0; in.value = pktbuf; in.length = 1; major = gss_wrap(&minor, vpninfo->gss_context[1], 0, GSS_C_QOP_DEFAULT, &in, NULL, &out); if (major != GSS_S_COMPLETE) { print_gss_err(vpninfo, "gss_wrap()", mech, major, minor); goto err; } pktbuf[0] = 1; pktbuf[1] = 2; store_be16(pktbuf + 2, out.length); memcpy(pktbuf + 4, out.value, out.length); free(out.value); vpn_progress(vpninfo, PRG_TRACE, _("Sending GSSAPI protection negotiation of %zu bytes\n"), out.length + 4); i = vpninfo->ssl_write(vpninfo, (void *)pktbuf, out.length + 4); if (i < 0) { vpn_progress(vpninfo, PRG_ERR, _("Failed to send GSSAPI protection response to proxy: %s\n"), strerror(-i)); goto err; } i = vpninfo->ssl_read(vpninfo, (void *)pktbuf, 4); if (i < 0) { vpn_progress(vpninfo, PRG_ERR, _("Failed to receive GSSAPI protection response from proxy: %s\n"), strerror(-i)); goto err; } in.length = load_be16(pktbuf + 2); in.value = pktbuf; i = vpninfo->ssl_read(vpninfo, (void *)pktbuf, in.length); if (i < 0) { vpn_progress(vpninfo, PRG_ERR, _("Failed to receive GSSAPI protection response from proxy: %s\n"), strerror(-i)); goto err; } vpn_progress(vpninfo, PRG_TRACE, _("Got GSSAPI protection response of %zu bytes: %02x %02x %02x %02x\n"), in.length, pktbuf[0], pktbuf[1], pktbuf[2], pktbuf[3]); major = gss_unwrap(&minor, vpninfo->gss_context[1], &in, &out, NULL, GSS_C_QOP_DEFAULT); if (major != GSS_S_COMPLETE) { print_gss_err(vpninfo, "gss_unwrap()", mech, major, minor); goto err; } if (out.length != 1) { vpn_progress(vpninfo, PRG_ERR, _("Invalid GSSAPI protection response from proxy (%zu bytes)\n"), out.length); gss_release_buffer(&minor, &out); goto err; } i = *(char *)out.value; gss_release_buffer(&minor, &out); if (i == 1) { vpn_progress(vpninfo, PRG_ERR, _("SOCKS proxy demands message integrity, which is not supported\n")); goto err; } else if (i == 2) { vpn_progress(vpninfo, PRG_ERR, _("SOCKS proxy demands message confidentiality, which is not supported\n")); goto err; } else if (i) { vpn_progress(vpninfo, PRG_ERR, _("SOCKS proxy demands protection unknown type 0x%02x\n"), (unsigned char)i); goto err; } ret = 0; } err: cleanup_gssapi_auth(vpninfo, 1, NULL); free(pktbuf); return ret; }