cssp.c revision a180a41bba1d50822df23fff0099e90b86638b89
/* -*- c-basic-offset: 8 -*-
rdesktop: A Remote Desktop Protocol client.
CredSSP layer and kerberos support.
Copyright 2012-2013 Henrik Andersson <hean01@cendio.se> for Cendio AB
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 "rdesktop.h"
extern RD_BOOL g_use_password_as_pin;
extern char *g_sc_csp_name;
extern char *g_sc_reader_name;
extern char *g_sc_card_name;
extern char *g_sc_container_name;
{ 9, (void *) "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" };
static void
{
unsigned char *data;
return;
}
static void
{
free(s);
}
static STREAM
{
return out;
}
static void
{
str);
do
{
if (ms != GSS_S_COMPLETE)
continue;
}
}
static RD_BOOL
{
int mech_found;
mech_found = 0;
if (mech == GSS_C_NO_OID)
return True;
if (!mech_set)
return False;
if (GSS_ERROR(major_status))
{
return False;
}
if (GSS_ERROR(major_status))
{
return False;
}
if (!mech_found)
return False;
return True;
}
static RD_BOOL
{
const char service_name[] = "TERMSRV";
if (GSS_ERROR(major_status))
{
return False;
}
return True;
}
static RD_BOOL
{
int conf_state;
if (major_status != GSS_S_COMPLETE)
{
return False;
}
if (!conf_state)
{
error("GSS Confidentiality failed, no encryption of message performed.");
return False;
}
// write enc data to out stream
return True;
}
static RD_BOOL
{
int conf_state;
if (major_status != GSS_S_COMPLETE)
{
return False;
}
return True;
}
#ifdef WITH_DEBUG_CREDSSP
void
{
fclose(f);
}
#endif
static STREAM
{
// domainName [0]
s_mark_end(&tmp);
// userName [1]
s_mark_end(&tmp);
// password [2]
s_mark_end(&tmp);
// build message
// cleanup
return out;
}
/* KeySpecs from wincrypt.h */
#define AT_KEYEXCHANGE 1
#define AT_SIGNATURE 2
static STREAM
char *csp)
{
// keySpec [0]
s_mark_end(&tmp);
// cardName [1]
if (card)
{
s_mark_end(&tmp);
}
// readerName [2]
if (reader)
{
s_mark_end(&tmp);
}
// containerName [3]
if (container)
{
s_mark_end(&tmp);
}
// cspName [4]
if (csp)
{
s_mark_end(&tmp);
}
// build message
// cleanup
return out;
}
static STREAM
{
// pin [0]
s_mark_end(&tmp);
// cspData[1]
// userHint [2]
{
s_mark_end(&tmp);
}
// domainHint [3]
{
s_mark_end(&tmp);
}
// build message
// cleanup
return out;
}
{
// credType [0]
if (g_use_password_as_pin == False)
{
}
else
{
}
s_mark_end(&tmp);
// credentials [1]
if (g_use_password_as_pin == False)
{
}
else
{
}
// Construct ASN.1 message
#endif
// cleanup
return out;
}
{
STREAM s;
// version [0]
s_mark_end(&tmp);
// negoToken [1]
{
}
// authInfo [2]
{
}
// pubKeyAuth [3]
{
}
// Construct ASN.1 Message
// Todo: can h1 be send directly instead of tcp_init() approach
s_mark_end(s);
streamsave(s, "tsrequest_out.raw");
#endif
tcp_send(s);
// cleanup
return True;
}
{
STREAM s;
int length;
int tagval;
if (s == NULL)
return False;
// verify ASN.1 header
if (s->p[0] != (BER_TAG_SEQUENCE | BER_TAG_CONSTRUCTED))
{
error("Expected BER_TAG_SEQUENCE|BER_TAG_CONSTRUCTED, got %x", s->p[0]);
return False;
}
// peek at first 4 bytes to get full message length
if (s->p[1] < 0x80)
else if (s->p[1] == 0x81)
else if (s->p[1] == 0x82)
else
return False;
// receive the remainings of message
streamsave(s, "tsrequest_in.raw");
#endif
// parse the response and into nego token
return False;
// version [0]
return False;
// negoToken [1]
if (token)
{
return False;
return False;
return False;
return False;
return False;
}
// pubKey [3]
if (pubkey)
{
return False;
return False;
}
return True;
}
{
int context_established = 0;
struct stream pubkey_cmp = { 0 };
// Verify that system gss support spnego
{
warning("CredSSP: System doesn't have support for desired authentication mechanism.\n");
return False;
}
// Get service name
{
warning("CredSSP: Failed to get target service name.\n");
return False;
}
// Establish tls connection to server
if (!tcp_tls_connect())
{
warning("CredSSP: Failed to establish TLS connection.\n");
return False;
}
#ifdef WITH_DEBUG_CREDSSP
#endif
// Enter the spnego loop
output_tok.length = 0;
minor_status = 0;
int i = 0;
do
{
cred,
&gss_ctx,
if (GSS_ERROR(major_status))
{
if (i == 0)
error("CredSSP: Initialize failed, do you have correct kerberos tgt initialized ?\n");
else
error("CredSSP: Negotiation failed.\n");
#ifdef WITH_DEBUG_CREDSSP
#endif
goto bail_out;
}
// validate required services
if (!(actual_services & GSS_C_CONF_FLAG))
{
error("CredSSP: Confidiality service required but is not available.\n");
goto bail_out;
}
// Send token to server
if (output_tok.length != 0)
{
s_mark_end(&token);
goto bail_out;
}
// Read token from server
{
goto bail_out;
}
else
{
// Send encrypted pubkey for verification to server
context_established = 1;
goto bail_out;
goto bail_out;
context_established = 1;
}
i++;
}
while (!context_established);
// read tsrequest response and decrypt for public key validation
goto bail_out;
goto bail_out;
// validate public key
{
error("CredSSP: Cannot guarantee integrity of server connection, MITM ? "
"(public key data mismatch)\n");
goto bail_out;
}
// Send TSCredentials
goto bail_out;
goto bail_out;
return True;
return False;
}