412 lines
9.3 KiB
C
412 lines
9.3 KiB
C
/**
|
|
* FreeRDP: A Remote Desktop Protocol Client
|
|
* Kerberos Auth Protocol DER Encode
|
|
*
|
|
* Copyright 2011 Samsung, Author Jiten Pathy
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "kerberos_encode.h"
|
|
|
|
int krb_encode_sequence_tag(STREAM* s, uint32 len)
|
|
{
|
|
uint8* bm;
|
|
uint32 totlen;
|
|
totlen = _GET_BYTE_LENGTH(len + 2) + 1;
|
|
stream_rewind(s, totlen);
|
|
stream_get_mark(s, bm);
|
|
der_write_sequence_tag(s, len);
|
|
stream_set_mark(s, bm);
|
|
return totlen;
|
|
}
|
|
|
|
int krb_encode_contextual_tag(STREAM* s, uint8 tag, uint32 len)
|
|
{
|
|
uint8* bm;
|
|
uint32 totlen;
|
|
totlen = _GET_BYTE_LENGTH(len) + 1;
|
|
stream_rewind(s, totlen);
|
|
stream_get_mark(s, bm);
|
|
der_write_contextual_tag(s, tag, len, true);
|
|
stream_set_mark(s, bm);
|
|
return totlen;
|
|
}
|
|
|
|
int krb_encode_application_tag(STREAM* s, uint8 tag, uint32 len)
|
|
{
|
|
uint8* bm;
|
|
uint32 totlen;
|
|
totlen = _GET_BYTE_LENGTH(len) + 1;
|
|
stream_rewind(s, totlen);
|
|
stream_get_mark(s, bm);
|
|
der_write_application_tag(s, tag, len);
|
|
stream_set_mark(s, bm);
|
|
return totlen;
|
|
}
|
|
|
|
int krb_encode_recordmark(STREAM* s, uint32 len)
|
|
{
|
|
uint8* bm;
|
|
stream_rewind(s, 4);
|
|
stream_get_mark(s, bm);
|
|
stream_write_uint32_be(s, len);
|
|
stream_set_mark(s, bm);
|
|
return 4;
|
|
}
|
|
|
|
int krb_encode_cname(STREAM* s, uint8 tag, char* cname)
|
|
{
|
|
uint8* bm;
|
|
uint32 len;
|
|
char* names[2];
|
|
|
|
names[0] = cname;
|
|
names[1] = NULL;
|
|
|
|
len = strlen(cname) + 15;
|
|
stream_rewind(s, len);
|
|
stream_get_mark(s, bm);
|
|
der_write_contextual_tag(s, tag, len - 2, true);
|
|
der_write_principal_name(s, NAME_TYPE_PRINCIPAL, names);
|
|
stream_set_mark(s, bm);
|
|
|
|
return len;
|
|
}
|
|
|
|
int krb_encode_sname(STREAM* s, uint8 tag, char* sname)
|
|
{
|
|
uint8* bm;
|
|
char* str;
|
|
char* names[3];
|
|
uint32 len, tmp;
|
|
|
|
len = strlen(sname) - 1 + 17;
|
|
|
|
stream_rewind(s, len);
|
|
stream_get_mark(s, bm);
|
|
|
|
der_write_contextual_tag(s, tag, len - 2, true);
|
|
|
|
tmp = strchr(sname, '/') - sname;
|
|
|
|
str = (char*) xzalloc(tmp + 1);
|
|
strncpy(str, sname, tmp);
|
|
|
|
names[0] = str;
|
|
names[1] = sname + tmp + 1;
|
|
names[2] = NULL;
|
|
|
|
der_write_principal_name(s, NAME_TYPE_SERVICE, names);
|
|
|
|
xfree(str);
|
|
stream_set_mark(s, bm);
|
|
|
|
return len;
|
|
}
|
|
|
|
int krb_encode_uint8(STREAM* s, uint8 tag, uint8 val)
|
|
{
|
|
uint8* bm;
|
|
stream_rewind(s, 5);
|
|
stream_get_mark(s, bm);
|
|
der_write_contextual_tag(s, tag, 3, true);
|
|
der_write_integer(s, val);
|
|
stream_set_mark(s, bm);
|
|
return 5;
|
|
}
|
|
|
|
int krb_encode_integer(STREAM* s, uint8 tag, int val)
|
|
{
|
|
uint8* bm;
|
|
uint32 totlen;
|
|
totlen = der_skip_integer(val);
|
|
stream_rewind(s, totlen + 2);
|
|
stream_get_mark(s, bm);
|
|
der_write_contextual_tag(s, tag, totlen, true);
|
|
der_write_integer(s, val);
|
|
stream_set_mark(s, bm);
|
|
return (totlen + 2);
|
|
}
|
|
|
|
int krb_encode_options(STREAM* s, uint8 tag, uint32 options)
|
|
{
|
|
uint8* bm;
|
|
stream_rewind(s, 9);
|
|
stream_get_mark(s, bm);
|
|
der_write_contextual_tag(s, tag, 7, true);
|
|
der_write_bit_string_tag(s, 5, 0);
|
|
stream_write_uint32_be(s, options);
|
|
stream_set_mark(s, bm);
|
|
return 9;
|
|
}
|
|
|
|
int krb_encode_string(STREAM* s, uint8 tag, char* str)
|
|
{
|
|
uint8* bm;
|
|
uint32 len;
|
|
len = strlen(str);
|
|
stream_rewind(s, len + 4);
|
|
stream_get_mark(s, bm);
|
|
der_write_contextual_tag(s, tag, len + 2, true);
|
|
der_write_general_string(s, str);
|
|
stream_set_mark(s, bm);
|
|
return (len + 4);
|
|
}
|
|
|
|
int krb_encode_time(STREAM* s, uint8 tag, char* strtime)
|
|
{
|
|
uint8* bm;
|
|
stream_rewind(s, 19);
|
|
stream_get_mark(s, bm);
|
|
der_write_contextual_tag(s, tag, 17, true);
|
|
der_write_generalized_time(s, strtime);
|
|
stream_set_mark(s, bm);
|
|
return 19;
|
|
}
|
|
|
|
int krb_encode_octet_string(STREAM* s, uint8* string, uint32 len)
|
|
{
|
|
uint8* bm;
|
|
uint32 totlen;
|
|
totlen = len + _GET_BYTE_LENGTH(len) + 1;
|
|
stream_rewind(s, totlen);
|
|
stream_get_mark(s, bm);
|
|
der_write_octet_string(s, string, len);
|
|
stream_set_mark(s, bm);
|
|
return totlen;
|
|
}
|
|
|
|
int krb_encode_encrypted_data(STREAM* s, KrbENCData* enc_data)
|
|
{
|
|
uint32 totlen;
|
|
|
|
/* Encrypted Data[2] */
|
|
totlen = krb_encode_octet_string(s, (enc_data->encblob).data, (enc_data->encblob).length);
|
|
totlen += krb_encode_contextual_tag(s, 2, totlen);
|
|
|
|
/* Encrypted key version no[1] */
|
|
if(enc_data->kvno != -1)
|
|
totlen += krb_encode_uint8(s, 1, enc_data->kvno);
|
|
|
|
/* Encrypted Type[0] */
|
|
totlen += krb_encode_integer(s, 0, enc_data->enctype);
|
|
|
|
totlen += krb_encode_sequence_tag(s, totlen);
|
|
return totlen;
|
|
}
|
|
|
|
int krb_encode_checksum(STREAM* s, rdpBlob* cksum, int cktype)
|
|
{
|
|
uint32 totlen;
|
|
|
|
/* Checksum Data[1] */
|
|
totlen = krb_encode_octet_string(s, cksum->data, cksum->length);
|
|
totlen += krb_encode_contextual_tag(s, 1, totlen);
|
|
|
|
/* Checksum Type[0] */
|
|
totlen += krb_encode_integer(s, 0, cktype);
|
|
|
|
totlen += krb_encode_sequence_tag(s, totlen);
|
|
return totlen;
|
|
}
|
|
|
|
int krb_encode_padata(STREAM* s, PAData** pa_data)
|
|
{
|
|
uint32 totlen;
|
|
uint32 curlen;
|
|
PAData** lpa_data;
|
|
|
|
totlen = 0;
|
|
lpa_data = pa_data;
|
|
|
|
while (*lpa_data != NULL)
|
|
{
|
|
/* padata value */
|
|
curlen = krb_encode_octet_string(s, ((*lpa_data)->value).data, ((*lpa_data)->value).length);
|
|
curlen += krb_encode_contextual_tag(s, 2, curlen);
|
|
|
|
/* padata type */
|
|
curlen += krb_encode_integer(s, 1, ((*lpa_data)->type));
|
|
curlen += krb_encode_sequence_tag(s, curlen);
|
|
totlen += curlen;
|
|
lpa_data++;
|
|
}
|
|
|
|
totlen += krb_encode_sequence_tag(s, totlen);
|
|
|
|
return totlen;
|
|
}
|
|
|
|
|
|
int krb_encode_authenticator(STREAM* s, Authenticator *krb_auth)
|
|
{
|
|
uint8* bm;
|
|
uint32 totlen, curlen;
|
|
|
|
/* seq no[7] */
|
|
stream_rewind(s, 8);
|
|
stream_get_mark(s, bm);
|
|
der_write_contextual_tag(s, 7, 6, true);
|
|
der_write_integer(s, krb_auth->seqno);
|
|
totlen = 8;
|
|
|
|
stream_set_mark(s, bm);
|
|
|
|
/* ctime[5] */
|
|
totlen += krb_encode_time(s, 5, krb_auth->ctime);
|
|
|
|
/* cusec[4] */
|
|
totlen += krb_encode_integer(s, 4, krb_auth->cusec);
|
|
|
|
/* cksum[3] */
|
|
curlen = krb_encode_checksum(s, krb_auth->cksum, krb_auth->cksumtype);
|
|
totlen += krb_encode_contextual_tag(s, 3, curlen) + curlen;
|
|
|
|
/* cname[2] */
|
|
totlen += krb_encode_cname(s, 2, krb_auth->cname);
|
|
|
|
/* crealm[1] */
|
|
totlen += krb_encode_string(s, 1, krb_auth->crealm);
|
|
|
|
/* avno[0] */
|
|
totlen += krb_encode_uint8(s, 0, krb_auth->avno);
|
|
|
|
totlen += krb_encode_sequence_tag(s, totlen);
|
|
totlen += krb_encode_application_tag(s, 2, totlen);
|
|
|
|
return totlen;
|
|
}
|
|
|
|
int krb_encode_ticket(STREAM* s, uint8 tag, Ticket* ticket)
|
|
{
|
|
uint32 totlen;
|
|
|
|
/* Encrypted DATA[3] */
|
|
totlen = krb_encode_encrypted_data(s, &(ticket->enc_part));
|
|
totlen += krb_encode_contextual_tag(s, 3, totlen);
|
|
|
|
/* sname[2] */
|
|
totlen += krb_encode_sname(s, 2, ticket->sname);
|
|
|
|
/* realm[1] */
|
|
totlen += krb_encode_string(s, 1, ticket->realm);
|
|
|
|
/* ticket vno[0] */
|
|
totlen += krb_encode_uint8(s, 0, ticket->tktvno);
|
|
|
|
totlen += krb_encode_sequence_tag(s, totlen);
|
|
totlen += krb_encode_application_tag(s, 1, totlen);
|
|
totlen += krb_encode_contextual_tag(s, tag, totlen);
|
|
|
|
return totlen;
|
|
}
|
|
|
|
int krb_encode_req_body(STREAM* s, KDCReqBody* req_body, int msgtype)
|
|
{
|
|
uint8* bm;
|
|
uint32 totlen;
|
|
totlen = 0;
|
|
|
|
/* ETYPE[8] we support des-cbc-crc, rc4-hmac and aes-128-ctc-hmac-sha1-96 only */
|
|
stream_rewind(s, 10);
|
|
stream_get_mark(s, bm);
|
|
der_write_contextual_tag(s, 8, 8, true);
|
|
der_write_sequence_tag(s, 6);
|
|
der_write_integer(s, ETYPE_RC4_HMAC);
|
|
der_write_integer(s, ETYPE_DES_CBC_CRC);
|
|
totlen += 10;
|
|
|
|
stream_set_mark(s, bm);
|
|
|
|
/* NONCE[7] */
|
|
stream_rewind(s, 8);
|
|
stream_get_mark(s, bm);
|
|
der_write_contextual_tag(s, 7, 6, true);
|
|
der_write_integer(s, req_body->nonce);
|
|
totlen += 8;
|
|
|
|
stream_set_mark(s, bm);
|
|
|
|
/* till[5] and rtime (tag 6)*/
|
|
totlen += krb_encode_time(s, 6, req_body->rtime);
|
|
totlen += krb_encode_time(s, 5, req_body->till);
|
|
|
|
/* SNAME[3]*/
|
|
totlen += krb_encode_sname(s, 3, req_body->sname);
|
|
|
|
/* REALM[2] */
|
|
totlen += krb_encode_string(s, 2, req_body->realm);
|
|
|
|
/* CNAME[1] */
|
|
totlen += krb_encode_cname(s, 1, req_body->cname);
|
|
|
|
/* KDCOptions[0]*/
|
|
totlen += krb_encode_options(s, 0, req_body->kdc_options);
|
|
|
|
/* KDC_BODY */
|
|
totlen += krb_encode_sequence_tag(s, totlen);
|
|
|
|
return totlen;
|
|
}
|
|
|
|
int krb_encode_apreq(STREAM* s, KrbAPREQ* krb_apreq)
|
|
{
|
|
uint32 totlen;
|
|
|
|
/* Encrypted Authenticator[4] */
|
|
totlen = krb_encode_encrypted_data(s, &(krb_apreq->enc_auth));
|
|
totlen += krb_encode_contextual_tag(s, 4, totlen);
|
|
|
|
/* Ticket[3] */
|
|
totlen += krb_encode_ticket(s, 3, krb_apreq->ticket);
|
|
|
|
/* APOPTIONS[2] */
|
|
totlen += krb_encode_options(s, 2, krb_apreq->ap_options);
|
|
|
|
/* MSGTYPE[1] */
|
|
totlen += krb_encode_uint8(s , 1, krb_apreq->type);
|
|
|
|
/* VERSION NO[0] */
|
|
totlen += krb_encode_uint8(s, 0, krb_apreq->pvno);
|
|
|
|
totlen += krb_encode_sequence_tag(s, totlen);
|
|
totlen += krb_encode_application_tag(s, krb_apreq->type, totlen);
|
|
|
|
return totlen;
|
|
}
|
|
|
|
int krb_encode_tgtreq(STREAM* s, KrbTGTREQ* krb_tgtreq)
|
|
{
|
|
uint32 totlen;
|
|
totlen = 0;
|
|
|
|
/* realm[3] optional */
|
|
if(krb_tgtreq->realm != NULL)
|
|
totlen += krb_encode_string(s, 3, krb_tgtreq->realm);
|
|
|
|
/* sname[2] optional */
|
|
if(krb_tgtreq->sname != NULL)
|
|
totlen += krb_encode_sname(s, 3, krb_tgtreq->sname);
|
|
|
|
/* msgtype[1] */
|
|
totlen += krb_encode_uint8(s , 1, krb_tgtreq->type);
|
|
|
|
/* pvno[0] */
|
|
totlen += krb_encode_uint8(s, 0, krb_tgtreq->pvno);
|
|
|
|
totlen += krb_encode_sequence_tag(s, totlen);
|
|
|
|
return totlen;
|
|
}
|