mirror of
https://github.com/FreeRDP/FreeRDP.git
synced 2024-11-24 02:14:11 +08:00
libfreerdp-auth: integrate Kerberos code from Jiten Pathy
This commit is contained in:
parent
386d815969
commit
6582dd3ebf
@ -276,7 +276,9 @@ struct rdp_settings
|
|||||||
boolean compression; /* 59 */
|
boolean compression; /* 59 */
|
||||||
uint32 performance_flags; /* 60 */
|
uint32 performance_flags; /* 60 */
|
||||||
rdpBlob* password_cookie; /* 61 */
|
rdpBlob* password_cookie; /* 61 */
|
||||||
uint32 paddingC[80 - 62]; /* 62 */
|
char* kerberos_kdc; /* 62 */
|
||||||
|
char* kerberos_realm; /* 63 */
|
||||||
|
uint32 paddingC[80 - 64]; /* 64 */
|
||||||
|
|
||||||
/* User Interface Parameters */
|
/* User Interface Parameters */
|
||||||
boolean sw_gdi; /* 80 */
|
boolean sw_gdi; /* 80 */
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#ifndef __BLOB_UTILS_H
|
#ifndef __BLOB_UTILS_H
|
||||||
#define __BLOB_UTILS_H
|
#define __BLOB_UTILS_H
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
#include <freerdp/api.h>
|
#include <freerdp/api.h>
|
||||||
|
|
||||||
struct rdp_blob
|
struct rdp_blob
|
||||||
@ -31,5 +32,6 @@ typedef struct rdp_blob rdpBlob;
|
|||||||
|
|
||||||
FREERDP_API void freerdp_blob_alloc(rdpBlob* blob, int length);
|
FREERDP_API void freerdp_blob_alloc(rdpBlob* blob, int length);
|
||||||
FREERDP_API void freerdp_blob_free(rdpBlob* blob);
|
FREERDP_API void freerdp_blob_free(rdpBlob* blob);
|
||||||
|
FREERDP_API void freerdp_blob_copy(rdpBlob* dstblob, rdpBlob* srcblob);
|
||||||
|
|
||||||
#endif /* __BLOB_UTILS_H */
|
#endif /* __BLOB_UTILS_H */
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#define __MEMORY_UTILS_H
|
#define __MEMORY_UTILS_H
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <ctype.h>
|
||||||
#include <freerdp/api.h>
|
#include <freerdp/api.h>
|
||||||
|
|
||||||
FREERDP_API void* xmalloc(size_t size);
|
FREERDP_API void* xmalloc(size_t size);
|
||||||
@ -28,6 +29,7 @@ FREERDP_API void* xzalloc(size_t size);
|
|||||||
FREERDP_API void* xrealloc(void* ptr, size_t size);
|
FREERDP_API void* xrealloc(void* ptr, size_t size);
|
||||||
FREERDP_API void xfree(void* ptr);
|
FREERDP_API void xfree(void* ptr);
|
||||||
FREERDP_API char* xstrdup(const char* str);
|
FREERDP_API char* xstrdup(const char* str);
|
||||||
|
FREERDP_API char* xstrtoup(const char* str);
|
||||||
|
|
||||||
#define xnew(_type) (_type*)xzalloc(sizeof(_type))
|
#define xnew(_type) (_type*)xzalloc(sizeof(_type))
|
||||||
|
|
||||||
|
@ -17,13 +17,27 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
set(FREERDP_AUTH_SRCS
|
set(FREERDP_SSPI_NTLM_SRCS
|
||||||
NTLM/ntlm.c
|
|
||||||
NTLM/ntlm.h
|
|
||||||
NTLM/ntlm_compute.c
|
NTLM/ntlm_compute.c
|
||||||
NTLM/ntlm_compute.h
|
NTLM/ntlm_compute.h
|
||||||
NTLM/ntlm_message.c
|
NTLM/ntlm_message.c
|
||||||
NTLM/ntlm_message.h
|
NTLM/ntlm_message.h
|
||||||
|
NTLM/ntlm.c
|
||||||
|
NTLM/ntlm.h)
|
||||||
|
|
||||||
|
set(FREERDP_SSPI_KERBEROS_SRCS
|
||||||
|
Kerberos/kerberos_crypto.c
|
||||||
|
Kerberos/kerberos_crypto.h
|
||||||
|
Kerberos/kerberos_decode.c
|
||||||
|
Kerberos/kerberos_decode.h
|
||||||
|
Kerberos/kerberos_encode.c
|
||||||
|
Kerberos/kerberos_encode.h
|
||||||
|
Kerberos/kerberos.c
|
||||||
|
Kerberos/kerberos.h)
|
||||||
|
|
||||||
|
set(FREERDP_AUTH_SRCS
|
||||||
|
${FREERDP_SSPI_NTLM_SRCS}
|
||||||
|
${FREERDP_SSPI_KERBEROS_SRCS}
|
||||||
sspi.c
|
sspi.c
|
||||||
sspi.h
|
sspi.h
|
||||||
credssp.c)
|
credssp.c)
|
||||||
|
1279
libfreerdp-auth/Kerberos/kerberos.c
Normal file
1279
libfreerdp-auth/Kerberos/kerberos.c
Normal file
File diff suppressed because it is too large
Load Diff
347
libfreerdp-auth/Kerberos/kerberos.h
Normal file
347
libfreerdp-auth/Kerberos/kerberos.h
Normal file
@ -0,0 +1,347 @@
|
|||||||
|
/**
|
||||||
|
* FreeRDP: A Remote Desktop Protocol Client
|
||||||
|
* Kerberos Auth Protocol
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __FREERDP_KRB_H
|
||||||
|
#define __FREERDP_KRB_H
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <arpa/nameser.h>
|
||||||
|
#include <resolv.h>
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <ws2tcpip.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <freerdp/auth/sspi.h>
|
||||||
|
#include <freerdp/types.h>
|
||||||
|
#include <freerdp/settings.h>
|
||||||
|
#include <freerdp/utils/stream.h>
|
||||||
|
#include <freerdp/utils/blob.h>
|
||||||
|
|
||||||
|
#define MSKRB_OID "1.2.840.48018.1.2.2"
|
||||||
|
#define STDKRB_OID "1.2.840.113554.1.2.2"
|
||||||
|
|
||||||
|
#define SERVICE "_kerberos."
|
||||||
|
#define KRB_VERSION 5
|
||||||
|
#define KRB_SERVER "krbtgt/"
|
||||||
|
#define APP_SERVER "TERMSRV/"
|
||||||
|
|
||||||
|
#define KRB_NAME_PRINCIPAL 1
|
||||||
|
#define KRB_NAME_SERVICE 2
|
||||||
|
|
||||||
|
/* KRB TAGS */
|
||||||
|
#define KRB_TAG_ASREQ 10
|
||||||
|
#define KRB_TAG_ASREP 11
|
||||||
|
#define KRB_TAG_TGSREQ 12
|
||||||
|
#define KRB_TAG_TGSREP 13
|
||||||
|
#define KRB_TAG_APREQ 14
|
||||||
|
#define KRB_TAG_APREP 15
|
||||||
|
#define KRB_TAG_ERROR 30
|
||||||
|
#define KRB_TAG_U2UTGTREQ 16
|
||||||
|
#define KRB_TAG_U2UTGTREP 16
|
||||||
|
|
||||||
|
#define NAME_TYPE_PRINCIPAL 1
|
||||||
|
#define NAME_TYPE_SERVICE 2
|
||||||
|
|
||||||
|
/* KRB ERROR */
|
||||||
|
#define KDC_ERR_PREAUTH_FAILED 24
|
||||||
|
#define KDC_ERR_PREAUTH_REQ 25
|
||||||
|
#define KRB_AP_ERR_SKEW 37
|
||||||
|
#define KDC_ERR_C_PRINCIPAL_UNKNOWN 6
|
||||||
|
|
||||||
|
#define PA_ENCTYPE_INFO 11
|
||||||
|
#define PA_ENCTYPE_INFO2 19
|
||||||
|
|
||||||
|
/* ENCRYPTION TYPE */
|
||||||
|
#define ETYPE_DES_CBC_CRC 1
|
||||||
|
#define ETYPE_DES_CBC_MD5 3
|
||||||
|
#define ETYPE_AES128_CTS_HMAC 17
|
||||||
|
#define ETYPE_AES256_CTS_HMAC 18
|
||||||
|
#define ETYPE_RC4_HMAC 23
|
||||||
|
|
||||||
|
/* CHECKSUM TYPE */
|
||||||
|
#define KRB_CKSUM_HMAC_MD5 -138
|
||||||
|
|
||||||
|
/* AD TYPE */
|
||||||
|
#define AD_IF_RELEVANT 1
|
||||||
|
|
||||||
|
#define GETUINT16( _s, _p) do{ \
|
||||||
|
*(_p) = (uint8)(_s)[0] << 8 | (uint8)(_s)[1]; \
|
||||||
|
(_s) += 2; } while (0)
|
||||||
|
#define _GET_BYTE_LENGTH(_n) (((_n) > 0xFF) ? 3 :(((_n) > 0x7F) ? 2 : 1))
|
||||||
|
|
||||||
|
enum _KRBCTX_STATE
|
||||||
|
{
|
||||||
|
KRB_STATE_INITIAL,
|
||||||
|
KRB_FAILOVER_NTLM,
|
||||||
|
KRB_ASREQ_OK,
|
||||||
|
KRB_ASREP_OK,
|
||||||
|
KRB_ASREP_ERR,
|
||||||
|
KRB_TGSREQ_OK,
|
||||||
|
KRB_TGSREP_OK,
|
||||||
|
KRB_TGSREP_ERR,
|
||||||
|
KRB_U2UTGTREQ_OK,
|
||||||
|
KRB_U2UTGTREP_OK,
|
||||||
|
KRB_APREQ_OK,
|
||||||
|
KRB_APREP_OK,
|
||||||
|
KRB_PACKET_ERROR,
|
||||||
|
KRB_STATE_FINAL
|
||||||
|
};
|
||||||
|
typedef enum _KRBCTX_STATE KRBCTX_STATE;
|
||||||
|
|
||||||
|
struct _kdc_srv_entry
|
||||||
|
{
|
||||||
|
struct _kdc_srv_entry* next;
|
||||||
|
uint16 priority;
|
||||||
|
uint16 weight;
|
||||||
|
uint16 port;
|
||||||
|
char* kdchost;
|
||||||
|
};
|
||||||
|
typedef struct _kdc_srv_entry KDCENTRY;
|
||||||
|
|
||||||
|
struct _PA_DATA
|
||||||
|
{
|
||||||
|
int type;
|
||||||
|
rdpBlob value;
|
||||||
|
};
|
||||||
|
typedef struct _PA_DATA PAData;
|
||||||
|
|
||||||
|
struct _AUTH_DATA
|
||||||
|
{
|
||||||
|
int ad_type;
|
||||||
|
uint8* ad_data;
|
||||||
|
};
|
||||||
|
typedef struct _AUTH_DATA AuthData;
|
||||||
|
|
||||||
|
struct _Krb_ENCData
|
||||||
|
{
|
||||||
|
sint32 enctype;
|
||||||
|
int kvno;
|
||||||
|
rdpBlob encblob;
|
||||||
|
};
|
||||||
|
typedef struct _Krb_ENCData KrbENCData;
|
||||||
|
|
||||||
|
struct _Krb_ENCKey
|
||||||
|
{
|
||||||
|
sint32 enctype;
|
||||||
|
rdpBlob skey;
|
||||||
|
};
|
||||||
|
typedef struct _Krb_ENCKey KrbENCKey;
|
||||||
|
|
||||||
|
struct _ENC_KDC_REPPART
|
||||||
|
{
|
||||||
|
KrbENCKey key;
|
||||||
|
int nonce;
|
||||||
|
uint32 flags;
|
||||||
|
uint32 authtime;
|
||||||
|
uint32 endtime;
|
||||||
|
char *realm;
|
||||||
|
char *sname;
|
||||||
|
};
|
||||||
|
typedef struct _ENC_KDC_REPPART ENCKDCREPPart;
|
||||||
|
|
||||||
|
struct _Krb_Ticket
|
||||||
|
{
|
||||||
|
int tktvno;
|
||||||
|
char* realm;
|
||||||
|
char* sname;
|
||||||
|
KrbENCData enc_part;
|
||||||
|
};
|
||||||
|
typedef struct _Krb_Ticket Ticket;
|
||||||
|
|
||||||
|
struct _Krb_Authenticator
|
||||||
|
{
|
||||||
|
int avno;
|
||||||
|
char* crealm;
|
||||||
|
char* cname;
|
||||||
|
int cksumtype;
|
||||||
|
rdpBlob* cksum;
|
||||||
|
uint32 cusec;
|
||||||
|
char* ctime;
|
||||||
|
uint32 seqno;
|
||||||
|
AuthData auth_data;
|
||||||
|
};
|
||||||
|
typedef struct _Krb_Authenticator Authenticator;
|
||||||
|
|
||||||
|
struct _KDC_REQ_BODY
|
||||||
|
{
|
||||||
|
uint32 kdc_options;
|
||||||
|
char* cname;
|
||||||
|
char* realm;
|
||||||
|
char* sname;
|
||||||
|
char* from;
|
||||||
|
char* till;
|
||||||
|
char* rtime;
|
||||||
|
uint32 nonce;
|
||||||
|
};
|
||||||
|
typedef struct _KDC_REQ_BODY KDCReqBody;
|
||||||
|
|
||||||
|
struct _KRB_KDCREP
|
||||||
|
{
|
||||||
|
int pvno;
|
||||||
|
int type;
|
||||||
|
PAData** padata;
|
||||||
|
char* realm;
|
||||||
|
char* cname;
|
||||||
|
Ticket etgt;
|
||||||
|
KrbENCData enc_part;
|
||||||
|
};
|
||||||
|
typedef struct _KRB_KDCREP KrbKDCREP;
|
||||||
|
|
||||||
|
struct _KRB_AS_REQ
|
||||||
|
{
|
||||||
|
int pvno;
|
||||||
|
int type;
|
||||||
|
boolean pa_pac_request;
|
||||||
|
PAData** padata;
|
||||||
|
KDCReqBody req_body;
|
||||||
|
};
|
||||||
|
typedef struct _KRB_AS_REQ KrbASREQ;
|
||||||
|
|
||||||
|
struct _KRB_TGS_REQ
|
||||||
|
{
|
||||||
|
int pvno;
|
||||||
|
int type;
|
||||||
|
boolean pa_pac_request;
|
||||||
|
PAData** padata;
|
||||||
|
KDCReqBody req_body;
|
||||||
|
};
|
||||||
|
typedef struct _KRB_TGS_REQ KrbTGSREQ;
|
||||||
|
|
||||||
|
struct _KRB_APREQ
|
||||||
|
{
|
||||||
|
int pvno;
|
||||||
|
int type;
|
||||||
|
uint32 ap_options;
|
||||||
|
Ticket* ticket;
|
||||||
|
KrbENCData enc_auth;
|
||||||
|
};
|
||||||
|
typedef struct _KRB_APREQ KrbAPREQ;
|
||||||
|
|
||||||
|
struct _KRB_ERROR
|
||||||
|
{
|
||||||
|
int pvno;
|
||||||
|
int type;
|
||||||
|
int errcode;
|
||||||
|
char* stime;
|
||||||
|
uint32 susec;
|
||||||
|
char* realm;
|
||||||
|
char* sname;
|
||||||
|
rdpBlob edata;
|
||||||
|
};
|
||||||
|
typedef struct _KRB_ERROR KrbERROR;
|
||||||
|
|
||||||
|
struct _KRB_ASREP
|
||||||
|
{
|
||||||
|
KrbKDCREP kdc_rep;
|
||||||
|
};
|
||||||
|
typedef struct _KRB_ASREP KrbASREP;
|
||||||
|
|
||||||
|
struct _KRB_TGSREP
|
||||||
|
{
|
||||||
|
KrbKDCREP kdc_rep;
|
||||||
|
};
|
||||||
|
typedef struct _KRB_TGSREP KrbTGSREP;
|
||||||
|
|
||||||
|
struct _KRB_TGTREQ
|
||||||
|
{
|
||||||
|
int pvno;
|
||||||
|
int type;
|
||||||
|
char* sname;
|
||||||
|
char* realm;
|
||||||
|
};
|
||||||
|
typedef struct _KRB_TGTREQ KrbTGTREQ;
|
||||||
|
|
||||||
|
struct _KRB_TGTREP
|
||||||
|
{
|
||||||
|
int pvno;
|
||||||
|
int type;
|
||||||
|
Ticket ticket;
|
||||||
|
};
|
||||||
|
typedef struct _KRB_TGTREP KrbTGTREP;
|
||||||
|
|
||||||
|
struct _KRB_CONTEXT
|
||||||
|
{
|
||||||
|
UNICONV* uniconv;
|
||||||
|
rdpSettings* settings;
|
||||||
|
int ksockfd;
|
||||||
|
uint16 krbport;
|
||||||
|
char* krbhost;
|
||||||
|
char* cname;
|
||||||
|
char* realm;
|
||||||
|
char* sname;
|
||||||
|
char* hostname;
|
||||||
|
SEC_AUTH_IDENTITY identity;
|
||||||
|
rdpBlob passwd;
|
||||||
|
sint32 enctype;
|
||||||
|
sint32 clockskew;
|
||||||
|
uint32 ctime;
|
||||||
|
uint32 nonce;
|
||||||
|
Ticket asticket;
|
||||||
|
KrbENCKey* askey;
|
||||||
|
Ticket tgsticket;
|
||||||
|
KrbENCKey* tgskey;
|
||||||
|
KRBCTX_STATE state;
|
||||||
|
CTXT_HANDLE context;
|
||||||
|
};
|
||||||
|
typedef struct _KRB_CONTEXT KRB_CONTEXT;
|
||||||
|
|
||||||
|
CTXT_HANDLE* krbctx_client_init(rdpSettings* settings, SEC_AUTH_IDENTITY* identity);
|
||||||
|
|
||||||
|
boolean tcp_is_ipaddr(const char* hostname);
|
||||||
|
char* get_utc_time(time_t t);
|
||||||
|
time_t get_local_time(char* str);
|
||||||
|
uint32 get_clock_skew(char* str);
|
||||||
|
char* get_dns_queryname(char *host, char* protocol);
|
||||||
|
int krb_get_realm(rdpSettings* settings);
|
||||||
|
KDCENTRY* krb_locate_kdc(rdpSettings* settings);
|
||||||
|
|
||||||
|
int krb_tcp_connect(KRB_CONTEXT* krb_ctx, KDCENTRY* entry);
|
||||||
|
int krb_tcp_send(KRB_CONTEXT* krb_ctx, uint8* data, uint32 length);
|
||||||
|
int krb_tcp_recv(KRB_CONTEXT* krb_ctx, uint8* data, uint32 length);
|
||||||
|
|
||||||
|
void krb_asreq_send(KRB_CONTEXT* krb_ctx, uint8 errcode);
|
||||||
|
int krb_asrep_recv(KRB_CONTEXT* krb_ctx);
|
||||||
|
|
||||||
|
void krb_tgsreq_send(KRB_CONTEXT* krb_ctx, uint8 errcode);
|
||||||
|
int krb_tgsrep_recv(KRB_CONTEXT* krb_ctx);
|
||||||
|
|
||||||
|
int krb_verify_kdcrep(KRB_CONTEXT* krb_ctx, KrbKDCREP* kdc_rep, int msgtype);
|
||||||
|
void krb_save_ticket(KRB_CONTEXT* krb_ctx, KrbKDCREP* kdc_rep);
|
||||||
|
|
||||||
|
KrbASREQ* krb_asreq_new(KRB_CONTEXT* krb_ctx, uint8 errcode);
|
||||||
|
KrbTGSREQ* krb_tgsreq_new(KRB_CONTEXT* krb_Rss, uint8 errcode);
|
||||||
|
KrbAPREQ* krb_apreq_new(KRB_CONTEXT* krb_ctx, Ticket* ticket, Authenticator* krb_auth);
|
||||||
|
|
||||||
|
void krb_ContextFree(KRB_CONTEXT* krb_ctx);
|
||||||
|
void krb_free_ticket(Ticket* ticket);
|
||||||
|
void krb_free_padata(PAData** padata);
|
||||||
|
void krb_free_req_body(KDCReqBody* req_body);
|
||||||
|
void krb_free_kdcrep(KrbKDCREP* kdc_rep);
|
||||||
|
void krb_free_reppart(ENCKDCREPPart* reppart);
|
||||||
|
void krb_free_asreq(KrbASREQ* krb_asreq);
|
||||||
|
void krb_free_asrep(KrbASREP* krb_asrep);
|
||||||
|
void krb_free_tgsreq(KrbTGSREQ* krb_tgsreq);
|
||||||
|
void krb_free_tgsrep(KrbTGSREP* krb_tgsrep);
|
||||||
|
void krb_free_krb_error(KrbERROR* krb_err);
|
||||||
|
|
||||||
|
#endif /* __FREERDP_KRB_H */
|
174
libfreerdp-auth/Kerberos/kerberos_crypto.c
Normal file
174
libfreerdp-auth/Kerberos/kerberos_crypto.c
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
/**
|
||||||
|
* FreeRDP: A Remote Desktop Protocol Client
|
||||||
|
* kerberos Crypto Support
|
||||||
|
*
|
||||||
|
* 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.h"
|
||||||
|
#include "kerberos_crypto.h"
|
||||||
|
|
||||||
|
uint8* crypto_md4_hash(rdpBlob* blob)
|
||||||
|
{
|
||||||
|
MD4_CTX md4_ctx;
|
||||||
|
uint8* hash;
|
||||||
|
hash = (uint8*)xzalloc(16);
|
||||||
|
MD4_Init(&md4_ctx);
|
||||||
|
MD4_Update(&md4_ctx, blob->data, blob->length);
|
||||||
|
MD4_Final(hash, &md4_ctx);
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
KrbENCKey* string2key(rdpBlob* string, sint8 enctype)
|
||||||
|
{
|
||||||
|
KrbENCKey* key;
|
||||||
|
key = xnew(KrbENCKey);
|
||||||
|
key->enctype = enctype;
|
||||||
|
switch(enctype)
|
||||||
|
{
|
||||||
|
case ETYPE_RC4_HMAC:
|
||||||
|
key->skey.data = crypto_md4_hash(string);
|
||||||
|
key->skey.length = 16;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
rdpBlob* crypto_kdcmsg_encrypt_rc4(rdpBlob* msg, uint8* key, uint32 msgtype)
|
||||||
|
{
|
||||||
|
rdpBlob* encmsg;
|
||||||
|
uint8* K1;
|
||||||
|
uint8* K3;
|
||||||
|
uint32 len;
|
||||||
|
krbEdata* edata;
|
||||||
|
CryptoRc4 rc4;
|
||||||
|
K1 = xzalloc(16);
|
||||||
|
K3 = xzalloc(16);
|
||||||
|
len = ((msg->length > 16) ? msg->length : 16);
|
||||||
|
len += sizeof(krbEdata);
|
||||||
|
edata = xzalloc(len);
|
||||||
|
encmsg = xnew(rdpBlob);
|
||||||
|
freerdp_blob_alloc(encmsg, len);
|
||||||
|
HMAC(EVP_md5(), (void*) key, 16, (uint8*)&msgtype, 4, (void*) K1, NULL);
|
||||||
|
crypto_nonce((uint8*)(edata->Confounder), 8);
|
||||||
|
memcpy(&(edata->data[0]), msg->data, msg->length);
|
||||||
|
HMAC(EVP_md5(), (void*) K1, 16, (uint8*)edata->Confounder, len - 16, (void*)&(edata->Checksum), NULL);
|
||||||
|
HMAC(EVP_md5(), (void*) K1, 16, (uint8*)&(edata->Checksum), 16, (void*)K3, NULL);
|
||||||
|
memcpy(encmsg->data, &(edata->Checksum), 16);
|
||||||
|
rc4 = crypto_rc4_init(K3, 16);
|
||||||
|
crypto_rc4(rc4, len - 16, (uint8*)edata->Confounder, (uint8*)(encmsg->data + 16));
|
||||||
|
crypto_rc4_free(rc4);
|
||||||
|
xfree(K1);
|
||||||
|
xfree(K3);
|
||||||
|
xfree(edata);
|
||||||
|
return encmsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
rdpBlob* crypto_kdcmsg_encrypt(rdpBlob* msg, KrbENCKey* key, uint32 msgtype)
|
||||||
|
{
|
||||||
|
switch(key->enctype)
|
||||||
|
{
|
||||||
|
case ETYPE_RC4_HMAC:
|
||||||
|
if(key->skey.length != 16)
|
||||||
|
return NULL;
|
||||||
|
return crypto_kdcmsg_encrypt_rc4(msg, key->skey.data, msgtype);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rdpBlob* crypto_kdcmsg_decrypt_rc4(rdpBlob* msg, uint8* key, uint32 msgtype)
|
||||||
|
{
|
||||||
|
rdpBlob* decmsg;
|
||||||
|
uint8* K1;
|
||||||
|
uint8* K3;
|
||||||
|
uint32 len;
|
||||||
|
krbEdata* edata;
|
||||||
|
CryptoRc4 rc4;
|
||||||
|
K1 = xzalloc(16);
|
||||||
|
K3 = xzalloc(16);
|
||||||
|
len = msg->length;
|
||||||
|
edata = xzalloc(len);
|
||||||
|
HMAC(EVP_md5(), (void*) key, 16, (uint8*)&msgtype, 4, (void*) K1, NULL);
|
||||||
|
HMAC(EVP_md5(), (void*) K1, 16, msg->data , 16, (void*)K3, NULL);
|
||||||
|
rc4 = crypto_rc4_init(K3, 16);
|
||||||
|
crypto_rc4(rc4, len - 16, (uint8*)(msg->data + 16), (uint8*)edata->Confounder);
|
||||||
|
crypto_rc4_free(rc4);
|
||||||
|
HMAC(EVP_md5(), (void*) K1, 16, (uint8*)edata->Confounder, len - 16, (void*)&(edata->Checksum), NULL);
|
||||||
|
if(memcmp(msg->data, &edata->Checksum, 16))
|
||||||
|
return NULL;
|
||||||
|
decmsg = xnew(rdpBlob);
|
||||||
|
freerdp_blob_alloc(decmsg, len);
|
||||||
|
memcpy(decmsg->data, edata, len);
|
||||||
|
xfree(K1);
|
||||||
|
xfree(K3);
|
||||||
|
xfree(edata);
|
||||||
|
return decmsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
rdpBlob* crypto_kdcmsg_decrypt(rdpBlob* msg, KrbENCKey* key, uint32 msgtype)
|
||||||
|
{
|
||||||
|
switch(key->enctype)
|
||||||
|
{
|
||||||
|
case ETYPE_RC4_HMAC:
|
||||||
|
if(key->skey.length != 16)
|
||||||
|
return NULL;
|
||||||
|
return crypto_kdcmsg_decrypt_rc4(msg, key->skey.data, msgtype);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rdpBlob* crypto_kdcmsg_cksum_hmacmd5(rdpBlob* msg, uint8* key, uint32 msgtype)
|
||||||
|
{
|
||||||
|
rdpBlob* cksum;
|
||||||
|
uint8* Ksign;
|
||||||
|
uint8* tmpdata;
|
||||||
|
uint8* tmp;
|
||||||
|
CryptoMd5 md5;
|
||||||
|
Ksign = xzalloc(16);
|
||||||
|
tmp = xzalloc(16);
|
||||||
|
cksum = xnew(rdpBlob);
|
||||||
|
freerdp_blob_alloc(cksum, 16);
|
||||||
|
tmpdata = xzalloc(msg->length + 4);
|
||||||
|
HMAC(EVP_md5(), (void*) key, 16, (uint8*)"signaturekey\0", 13, (void*) Ksign, NULL);
|
||||||
|
memcpy(tmpdata, (void*)&msgtype, 4);
|
||||||
|
memcpy(tmpdata + 4, msg->data, msg->length);
|
||||||
|
md5 = crypto_md5_init();
|
||||||
|
crypto_md5_update(md5, tmpdata, msg->length + 4);
|
||||||
|
crypto_md5_final(md5, tmp);
|
||||||
|
HMAC(EVP_md5(), (void*) Ksign, 16, (uint8*)tmp, 16, (void*) cksum->data, NULL);
|
||||||
|
return cksum;
|
||||||
|
}
|
||||||
|
|
||||||
|
rdpBlob* crypto_kdcmsg_cksum(rdpBlob* msg, KrbENCKey* key, uint32 msgtype)
|
||||||
|
{
|
||||||
|
switch(key->enctype)
|
||||||
|
{
|
||||||
|
case ETYPE_RC4_HMAC:
|
||||||
|
if(key->skey.length != 16)
|
||||||
|
return NULL;
|
||||||
|
return crypto_kdcmsg_cksum_hmacmd5(msg, key->skey.data, msgtype);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_cksum_type(uint32 enctype)
|
||||||
|
{
|
||||||
|
switch(enctype)
|
||||||
|
{
|
||||||
|
case ETYPE_RC4_HMAC:
|
||||||
|
return KRB_CKSUM_HMAC_MD5;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
56
libfreerdp-auth/Kerberos/kerberos_crypto.h
Normal file
56
libfreerdp-auth/Kerberos/kerberos_crypto.h
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
/**
|
||||||
|
* FreeRDP: A Remote Desktop Protocol Client
|
||||||
|
* kerberos Crypto Support
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __KRB_CRYPTO_H
|
||||||
|
#define __KRB_CRYPTO_H
|
||||||
|
|
||||||
|
#include <openssl/err.h>
|
||||||
|
#include <openssl/rc4.h>
|
||||||
|
#include <openssl/md4.h>
|
||||||
|
#include <openssl/md5.h>
|
||||||
|
#include <openssl/sha.h>
|
||||||
|
#include <openssl/hmac.h>
|
||||||
|
#include <openssl/bn.h>
|
||||||
|
#include <openssl/rand.h>
|
||||||
|
|
||||||
|
#include <freerdp/crypto/crypto.h>
|
||||||
|
|
||||||
|
struct _KRB_EDATA
|
||||||
|
{
|
||||||
|
uint8 Checksum[16];
|
||||||
|
uint8 Confounder[8];
|
||||||
|
uint8* data[0];
|
||||||
|
};
|
||||||
|
typedef struct _KRB_EDATA krbEdata;
|
||||||
|
|
||||||
|
int get_cksum_type(uint32 enctype);
|
||||||
|
|
||||||
|
uint8* crypto_md4_hash(rdpBlob* blob);
|
||||||
|
KrbENCKey* string2key(rdpBlob* string, sint8 enctype);
|
||||||
|
|
||||||
|
rdpBlob* crypto_kdcmsg_encrypt_rc4(rdpBlob* msg, uint8* key, uint32 msgtype);
|
||||||
|
rdpBlob* crypto_kdcmsg_encrypt(rdpBlob* msg, KrbENCKey* key, uint32 msgtype);
|
||||||
|
|
||||||
|
rdpBlob* crypto_kdcmsg_decrypt_rc4(rdpBlob* msg, uint8* key, uint32 msgtype);
|
||||||
|
rdpBlob* crypto_kdcmsg_decrypt(rdpBlob* msg, KrbENCKey* key, uint32 msgtype);
|
||||||
|
|
||||||
|
rdpBlob* crypto_kdcmsg_cksum_hmacmd5(rdpBlob* msg, uint8* key, uint32 msgtype);
|
||||||
|
rdpBlob* crypto_kdcmsg_cksum(rdpBlob* msg, KrbENCKey* key, uint32 msgtype);
|
||||||
|
|
||||||
|
#endif /* __KRB_CRYPTO_H */
|
834
libfreerdp-auth/Kerberos/kerberos_decode.c
Normal file
834
libfreerdp-auth/Kerberos/kerberos_decode.c
Normal file
@ -0,0 +1,834 @@
|
|||||||
|
/**
|
||||||
|
* FreeRDP: A Remote Desktop Protocol Client
|
||||||
|
* Kerberos Auth Protocol DER Decode
|
||||||
|
*
|
||||||
|
* 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_decode.h"
|
||||||
|
|
||||||
|
int krb_decode_application_tag(STREAM* s, uint8 tag, int *length)
|
||||||
|
{
|
||||||
|
uint8* bm;
|
||||||
|
stream_get_mark(s, bm);
|
||||||
|
|
||||||
|
if(!der_read_application_tag(s, tag, length))
|
||||||
|
{
|
||||||
|
stream_set_mark(s, bm);
|
||||||
|
*length = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return (s->p - bm);
|
||||||
|
}
|
||||||
|
|
||||||
|
int krb_decode_sequence_tag(STREAM* s, int *length)
|
||||||
|
{
|
||||||
|
uint8* bm;
|
||||||
|
stream_get_mark(s, bm);
|
||||||
|
|
||||||
|
if(!der_read_sequence_tag(s, length))
|
||||||
|
{
|
||||||
|
stream_set_mark(s, bm);
|
||||||
|
*length = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return (s->p - bm);
|
||||||
|
}
|
||||||
|
|
||||||
|
int krb_decode_contextual_tag(STREAM* s, uint8 tag, int *length)
|
||||||
|
{
|
||||||
|
uint8* bm;
|
||||||
|
stream_get_mark(s, bm);
|
||||||
|
|
||||||
|
if(!der_read_contextual_tag(s, tag, length, true))
|
||||||
|
{
|
||||||
|
stream_set_mark(s, bm);
|
||||||
|
*length = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return (s->p - bm);
|
||||||
|
}
|
||||||
|
|
||||||
|
int krb_skip_contextual_tag(STREAM* s, uint8 tag)
|
||||||
|
{
|
||||||
|
uint8* bm;
|
||||||
|
int length;
|
||||||
|
stream_get_mark(s, bm);
|
||||||
|
|
||||||
|
if(!der_read_contextual_tag(s, tag, &length, true))
|
||||||
|
{
|
||||||
|
stream_set_mark(s, bm);
|
||||||
|
length = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
stream_seek(s, length);
|
||||||
|
return (s->p - bm);
|
||||||
|
}
|
||||||
|
|
||||||
|
int krb_decode_integer(STREAM* s, uint32* value)
|
||||||
|
{
|
||||||
|
uint8* bm;
|
||||||
|
stream_get_mark(s, bm);
|
||||||
|
|
||||||
|
if(!der_read_integer(s, value))
|
||||||
|
{
|
||||||
|
stream_set_mark(s, bm);
|
||||||
|
*value = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return (s->p - bm);
|
||||||
|
}
|
||||||
|
|
||||||
|
int krb_decode_time(STREAM* s, uint8 tag, char** str)
|
||||||
|
{
|
||||||
|
uint8* bm;
|
||||||
|
int tmp;
|
||||||
|
stream_get_mark(s, bm);
|
||||||
|
|
||||||
|
if((krb_decode_contextual_tag(s, tag, &tmp) == 0) || (tmp != 17) || !der_read_generalized_time(s, str))
|
||||||
|
{
|
||||||
|
stream_set_mark(s, bm);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return (s->p - bm);
|
||||||
|
}
|
||||||
|
|
||||||
|
int krb_decode_int(STREAM* s, uint8 tag, uint32* result)
|
||||||
|
{
|
||||||
|
uint8* bm;
|
||||||
|
int totlen, len, tmp;
|
||||||
|
totlen = 0;
|
||||||
|
stream_get_mark(s, bm);
|
||||||
|
|
||||||
|
if((len = krb_decode_contextual_tag(s, tag, &tmp)) == 0)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
|
||||||
|
if(((len = krb_decode_integer(s, result)) == 0) || (tmp != len))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
return totlen;
|
||||||
|
|
||||||
|
err:
|
||||||
|
stream_set_mark(s, bm);
|
||||||
|
*result = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int krb_decode_flags(STREAM* s, uint8 tag, uint32* flags)
|
||||||
|
{
|
||||||
|
uint8* bm;
|
||||||
|
int len, tmp, verlen;
|
||||||
|
verlen = 9;
|
||||||
|
stream_get_mark(s, bm);
|
||||||
|
|
||||||
|
if(((len = krb_decode_contextual_tag(s, tag, &tmp)) == 0) || (len != (verlen - tmp)))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
verlen -= len;
|
||||||
|
|
||||||
|
if(!der_read_bit_string(s, &tmp, (uint8*)&len) || (tmp != 5))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
stream_read_uint32_be(s, *flags);
|
||||||
|
return 9;
|
||||||
|
|
||||||
|
err:
|
||||||
|
stream_set_mark(s, bm);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int krb_decode_string(STREAM* s, uint8 tag, char** str)
|
||||||
|
{
|
||||||
|
uint8* bm;
|
||||||
|
int totlen, len, tmp;
|
||||||
|
totlen = 0;
|
||||||
|
stream_get_mark(s, bm);
|
||||||
|
|
||||||
|
if((len = krb_decode_contextual_tag(s, tag, &tmp)) == 0)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
|
||||||
|
if(((*str = der_read_general_string(s, &len)) == NULL) || tmp != len)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
return totlen;
|
||||||
|
|
||||||
|
err:
|
||||||
|
stream_set_mark(s, bm);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int krb_decode_octet_string(STREAM* s, uint8 tag, uint8** data, int* length)
|
||||||
|
{
|
||||||
|
uint8* bm;
|
||||||
|
int totlen, len, tmp, verlen;
|
||||||
|
totlen = 0;
|
||||||
|
stream_get_mark(s, bm);
|
||||||
|
|
||||||
|
if((len = krb_decode_contextual_tag(s, tag, &verlen)) == 0)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
|
||||||
|
if(!der_read_octet_string(s, &tmp))
|
||||||
|
{
|
||||||
|
stream_set_mark(s, bm);
|
||||||
|
*length = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
totlen += tmp + _GET_BYTE_LENGTH(tmp) + 1;
|
||||||
|
verlen -= (tmp + _GET_BYTE_LENGTH(tmp) + 1);
|
||||||
|
|
||||||
|
if(verlen != 0)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
*data = xzalloc(tmp);
|
||||||
|
stream_read(s, *data, tmp);
|
||||||
|
*length = tmp;
|
||||||
|
|
||||||
|
return totlen;
|
||||||
|
|
||||||
|
err:
|
||||||
|
stream_set_mark(s, bm);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int krb_decode_cname(STREAM* s, uint8 tag, char** str)
|
||||||
|
{
|
||||||
|
uint8* bm;
|
||||||
|
int totlen, len, tmp, type, verlen;
|
||||||
|
totlen = 0;
|
||||||
|
stream_get_mark(s, bm);
|
||||||
|
|
||||||
|
/* Contextual tag */
|
||||||
|
if((len = krb_decode_contextual_tag(s, tag, &verlen)) == 0)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
|
||||||
|
/* cname sequence tag */
|
||||||
|
if(((len = krb_decode_sequence_tag(s, &tmp)) == 0) || (tmp != (verlen - len)))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
verlen -= len;
|
||||||
|
|
||||||
|
/* cname name type[0] */
|
||||||
|
if((verlen <= 0) || ((len = krb_decode_int(s, 0, (uint32*)&type)) == 0) || (type != KRB_NAME_PRINCIPAL))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
verlen -= len;
|
||||||
|
|
||||||
|
/* cname name[1] */
|
||||||
|
if((verlen <= 0) || ((len = krb_decode_contextual_tag(s, 1, &tmp)) == 0) || (tmp != (verlen - len)))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
verlen -= len;
|
||||||
|
|
||||||
|
if((verlen <= 0) || ((len = krb_decode_sequence_tag(s, &tmp)) == 0) || (tmp != (verlen - len)))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
verlen -= len;
|
||||||
|
|
||||||
|
if(((*str = der_read_general_string(s, &len)) == NULL))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
|
||||||
|
if(verlen != len)
|
||||||
|
{
|
||||||
|
xfree(str);
|
||||||
|
*str = NULL;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return totlen;
|
||||||
|
|
||||||
|
err:
|
||||||
|
stream_set_mark(s, bm);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int krb_decode_sname(STREAM* s, uint8 tag, char** str)
|
||||||
|
{
|
||||||
|
uint8* bm;
|
||||||
|
int totlen, len, tmp, type, verlen;
|
||||||
|
char* name;
|
||||||
|
char* realm;
|
||||||
|
totlen = 0;
|
||||||
|
stream_get_mark(s, bm);
|
||||||
|
|
||||||
|
/* Contextual tag */
|
||||||
|
if((len = krb_decode_contextual_tag(s, tag, &verlen)) == 0)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
|
||||||
|
/* sname sequence tag */
|
||||||
|
if(((len = krb_decode_sequence_tag(s, &tmp)) == 0) || (tmp != (verlen - len)))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
verlen -= len;
|
||||||
|
|
||||||
|
/* sname name type[0] */
|
||||||
|
if((verlen <= 0) || ((len = krb_decode_int(s, 0, (uint32*)&type)) == 0) || (type != KRB_NAME_SERVICE))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
verlen -= len;
|
||||||
|
|
||||||
|
/* sname name & realm[1] */
|
||||||
|
if((verlen <= 0) || ((len = krb_decode_contextual_tag(s, 1, &tmp)) == 0) || (tmp != (verlen - len)))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
verlen -= len;
|
||||||
|
|
||||||
|
if((verlen <= 0) || ((len = krb_decode_sequence_tag(s, &tmp)) == 0) || (tmp != (verlen - len)))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
verlen -= len;
|
||||||
|
|
||||||
|
if(((name = der_read_general_string(s, &len)) == NULL))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
verlen -= len;
|
||||||
|
|
||||||
|
if(((realm = der_read_general_string(s, &len)) == NULL))
|
||||||
|
{
|
||||||
|
xfree(name);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
|
||||||
|
if(verlen != len)
|
||||||
|
{
|
||||||
|
xfree(name);
|
||||||
|
xfree(realm);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
*str = xzalloc(strlen(name) + strlen(realm) + 2);
|
||||||
|
strcpy(*str, name);
|
||||||
|
strcat(*str, "/");
|
||||||
|
strcat(*str, realm);
|
||||||
|
|
||||||
|
xfree(name);
|
||||||
|
xfree(realm);
|
||||||
|
return totlen;
|
||||||
|
|
||||||
|
err:
|
||||||
|
stream_set_mark(s, bm);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int krb_decode_enckey(STREAM* s, KrbENCKey* key)
|
||||||
|
{
|
||||||
|
uint8* bm;
|
||||||
|
int totlen, len, verlen;
|
||||||
|
totlen = 0;
|
||||||
|
stream_get_mark(s, bm);
|
||||||
|
|
||||||
|
if((len = krb_decode_sequence_tag(s, &verlen)) == 0)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
|
||||||
|
/* enctype[0] */
|
||||||
|
if((len = krb_decode_int(s, 0, (uint32*)&(key->enctype))) == 0)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
verlen -= len;
|
||||||
|
|
||||||
|
/* keyvalue[1] */
|
||||||
|
if((verlen <= 0) || ((len = krb_decode_octet_string(s, 1, (uint8**)&(key->skey.data), &(key->skey.length))) == 0))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
|
||||||
|
if(verlen != len)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
return totlen;
|
||||||
|
|
||||||
|
err:
|
||||||
|
stream_set_mark(s, bm);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int krb_decode_encrypted_data(STREAM* s, KrbENCData* enc_data)
|
||||||
|
{
|
||||||
|
uint8* bm;
|
||||||
|
int totlen, len, verlen;
|
||||||
|
totlen = 0;
|
||||||
|
stream_get_mark(s, bm);
|
||||||
|
|
||||||
|
if((len = krb_decode_sequence_tag(s, &verlen)) == 0)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
|
||||||
|
/* enctype[0] */
|
||||||
|
if(((len = krb_decode_int(s, 0, (uint32*)&(enc_data->enctype))) == 0))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
verlen -= len;
|
||||||
|
|
||||||
|
/* kvno[1] OPTIONAL */
|
||||||
|
if((verlen <= 0))
|
||||||
|
goto err;
|
||||||
|
len = krb_decode_int(s, 1, (uint32*)&(enc_data->kvno));
|
||||||
|
totlen += len;
|
||||||
|
verlen -= len;
|
||||||
|
|
||||||
|
/* data[2] */
|
||||||
|
if((verlen <= 0) || ((len = krb_decode_octet_string(s, 2, (uint8**)&(enc_data->encblob.data), &(enc_data->encblob.length))) == 0))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
|
||||||
|
if(verlen != len)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
return totlen;
|
||||||
|
|
||||||
|
err:
|
||||||
|
stream_set_mark(s, bm);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int krb_decode_ticket(STREAM* s, uint8 tag, Ticket* ticket)
|
||||||
|
{
|
||||||
|
uint8* bm;
|
||||||
|
int totlen, len, tmp, verlen;
|
||||||
|
totlen = 0;
|
||||||
|
stream_get_mark(s, bm);
|
||||||
|
|
||||||
|
/* Contextual tag */
|
||||||
|
if((len = krb_decode_contextual_tag(s, tag, &verlen)) == 0)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
|
||||||
|
/* Application Tag 1 */
|
||||||
|
if(((len = krb_decode_application_tag(s, 1, &tmp)) == 0) || (tmp != (verlen - len)))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
verlen -=len;
|
||||||
|
|
||||||
|
if((verlen <= 0) || ((len = krb_decode_sequence_tag(s, &tmp)) == 0) || (tmp != (verlen - len)))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
verlen -= len;
|
||||||
|
|
||||||
|
/* tkt vno[0] */
|
||||||
|
if((verlen <= 0) || ((len = krb_decode_int(s, 0, (uint32*)&(ticket->tktvno))) == 0))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
verlen -= len;
|
||||||
|
|
||||||
|
/* realm[1] */
|
||||||
|
if((verlen <= 0) || ((len = krb_decode_string(s, 1, &(ticket->realm))) == 0))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
verlen -= len;
|
||||||
|
|
||||||
|
/* sname[2] */
|
||||||
|
if((verlen <= 0) || ((len = krb_decode_sname(s, 2, &(ticket->sname))) == 0))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
verlen -= len;
|
||||||
|
|
||||||
|
/* Encrypted Data[3] */
|
||||||
|
if((verlen <= 0) || ((len = krb_decode_contextual_tag(s, 3, &tmp)) == 0) || (tmp != (verlen - len)))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
verlen -= len;
|
||||||
|
|
||||||
|
if((verlen <= 0) || ((len = krb_decode_encrypted_data(s, &(ticket->enc_part))) == 0))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
|
||||||
|
if(verlen != len)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
return totlen;
|
||||||
|
|
||||||
|
err:
|
||||||
|
stream_set_mark(s, bm);
|
||||||
|
krb_free_ticket(ticket);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int krb_decode_kdc_rep(STREAM* s, KrbKDCREP* kdc_rep, sint32 maxlen)
|
||||||
|
{
|
||||||
|
uint8* bm;
|
||||||
|
int totlen, len, tmp, verlen;
|
||||||
|
totlen = 0;
|
||||||
|
stream_get_mark(s, bm);
|
||||||
|
|
||||||
|
/* sequence tag */
|
||||||
|
if(((len = krb_decode_sequence_tag(s, &verlen)) == 0) || (verlen != (maxlen - len)))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
|
||||||
|
/* version no[0] */
|
||||||
|
if(((len = krb_decode_int(s, 0, (uint32*)&(kdc_rep->pvno))) == 0))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
verlen -= len;
|
||||||
|
|
||||||
|
/* msg type[1] */
|
||||||
|
if((verlen <= 0) || ((len = krb_decode_int(s, 1, (uint32*)&(kdc_rep->type))) == 0))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
verlen -= len;
|
||||||
|
|
||||||
|
/* PA-DATA[2] OPTIONAL */
|
||||||
|
if(verlen <= 0)
|
||||||
|
goto err;
|
||||||
|
len = krb_decode_contextual_tag(s, 2, &tmp);
|
||||||
|
totlen += len + tmp;
|
||||||
|
verlen -= (len + tmp);
|
||||||
|
stream_seek(s, tmp);
|
||||||
|
|
||||||
|
/* crealm[3] */
|
||||||
|
if((verlen <= 0) || ((len = krb_decode_string(s, 3, &(kdc_rep->realm))) == 0))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
verlen -= len;
|
||||||
|
|
||||||
|
/* cname[4] */
|
||||||
|
if((verlen <= 0) || ((len = krb_decode_cname(s, 4, &(kdc_rep->cname))) == 0))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
verlen -= len;
|
||||||
|
|
||||||
|
/* ticket[5] */
|
||||||
|
if((verlen <= 0) || ((len = krb_decode_ticket(s, 5, &(kdc_rep->etgt))) == 0))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
verlen -= len;
|
||||||
|
|
||||||
|
/* enc_part[6] */
|
||||||
|
if((verlen <= 0) || ((len = krb_decode_contextual_tag(s, 6, &tmp)) == 0) || (tmp != (verlen - len)))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
verlen -= len;
|
||||||
|
|
||||||
|
if((verlen <= 0) || ((len = krb_decode_encrypted_data(s, &(kdc_rep->enc_part))) == 0))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
|
||||||
|
if(verlen != len)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
return totlen;
|
||||||
|
|
||||||
|
err:
|
||||||
|
krb_free_kdcrep(kdc_rep);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int krb_decode_krb_error(STREAM* s, KrbERROR* krb_err, sint32 maxlen)
|
||||||
|
{
|
||||||
|
uint8* bm;
|
||||||
|
int totlen, len, verlen;
|
||||||
|
int i, tag;
|
||||||
|
totlen = tag = 0;
|
||||||
|
stream_get_mark(s, bm);
|
||||||
|
|
||||||
|
/* sequence tag */
|
||||||
|
if(((len = krb_decode_sequence_tag(s, &verlen)) == 0) || (verlen != (maxlen - len)))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
|
||||||
|
/* version no[0] */
|
||||||
|
if(((len = krb_decode_int(s, tag++, (uint32*)&(krb_err->pvno))) == 0))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
verlen -= len;
|
||||||
|
|
||||||
|
/* msg type[1] */
|
||||||
|
if((verlen <= 0) || ((len = krb_decode_int(s, tag++, (uint32*)&(krb_err->type))) == 0))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
verlen -= len;
|
||||||
|
|
||||||
|
/* skip tag 2 3 */
|
||||||
|
for(i = 2;i < 4;i++)
|
||||||
|
{
|
||||||
|
if(verlen <= 0)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
len = krb_skip_contextual_tag(s, tag++);
|
||||||
|
verlen -= len;
|
||||||
|
totlen += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* stime[4] */
|
||||||
|
if((verlen <= 0) || ((len = krb_decode_time(s, tag++, &(krb_err->stime))) == 0))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
verlen -= len;
|
||||||
|
|
||||||
|
/* skip tag 5 */
|
||||||
|
if(verlen <= 0)
|
||||||
|
goto err;
|
||||||
|
len = krb_skip_contextual_tag(s, tag++);
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
verlen -= len;
|
||||||
|
|
||||||
|
/* error code[6] */
|
||||||
|
if((verlen <= 0) || ((len = krb_decode_int(s, tag++, (uint32*)&(krb_err->errcode))) == 0))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
verlen -= len;
|
||||||
|
|
||||||
|
/* skip tag 7, 8, 9, 10, 11 */
|
||||||
|
for(i = 7;i < 12;i++)
|
||||||
|
{
|
||||||
|
if(verlen <= 0)
|
||||||
|
goto err;
|
||||||
|
else if(verlen == 0)
|
||||||
|
return totlen;
|
||||||
|
|
||||||
|
len = krb_skip_contextual_tag(s, tag++);
|
||||||
|
verlen -= len;
|
||||||
|
totlen += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* edata (tag 12) */
|
||||||
|
if((verlen < 0) || ((len = krb_decode_octet_string(s, tag++, (uint8**)&(krb_err->edata.data), &(krb_err->edata.length))) == 0))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
|
||||||
|
if(verlen != len)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
return totlen;
|
||||||
|
|
||||||
|
err:
|
||||||
|
krb_free_krb_error(krb_err);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ENCKDCREPPart* krb_decode_enc_reppart(rdpBlob* msg, uint8 apptag)
|
||||||
|
{
|
||||||
|
int len, tmp, verlen;
|
||||||
|
STREAM* s;
|
||||||
|
char* timestr;
|
||||||
|
ENCKDCREPPart* reppart;
|
||||||
|
|
||||||
|
reppart = xnew(ENCKDCREPPart);
|
||||||
|
s = stream_new(0);
|
||||||
|
stream_attach(s, msg->data + 24, msg->length);
|
||||||
|
verlen = msg->length - 24;
|
||||||
|
|
||||||
|
/* application tag */
|
||||||
|
if((verlen <= 0) || ((len = krb_decode_application_tag(s, apptag, &tmp)) == 0) || (tmp != (verlen - len)))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
verlen -= len;
|
||||||
|
|
||||||
|
/* sequence tag */
|
||||||
|
if((verlen <= 0) || ((len = krb_decode_sequence_tag(s, &tmp)) == 0) || (tmp != (verlen - len)))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
verlen -= len;
|
||||||
|
|
||||||
|
/* skey[0] */
|
||||||
|
if((verlen <= 0) || ((len = krb_decode_contextual_tag(s, 0, &tmp)) == 0))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
verlen -= len;
|
||||||
|
|
||||||
|
if((verlen <= 0) || ((len = krb_decode_enckey(s, &(reppart->key))) == 0))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
verlen -= len;
|
||||||
|
|
||||||
|
/* skip tag 1 (last req) */
|
||||||
|
if(verlen <= 0)
|
||||||
|
goto err;
|
||||||
|
len = krb_skip_contextual_tag(s, 1);
|
||||||
|
|
||||||
|
verlen -= len;
|
||||||
|
|
||||||
|
/* nonce[2] */
|
||||||
|
|
||||||
|
if((verlen <= 0) || ((len = krb_decode_int(s, 2, (uint32*)&(reppart->nonce))) == 0))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
verlen -= len;
|
||||||
|
|
||||||
|
/* skip tag 3 (key expiration) */
|
||||||
|
if(verlen <= 0)
|
||||||
|
goto err;
|
||||||
|
len = krb_skip_contextual_tag(s, 3);
|
||||||
|
|
||||||
|
verlen -= len;
|
||||||
|
|
||||||
|
/* TicketFlags[4] */
|
||||||
|
if((verlen <= 0) || ((len = krb_decode_flags(s, 4, (uint32*)&(reppart->flags))) == 0))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
verlen -= len;
|
||||||
|
|
||||||
|
/* authtime[5] */
|
||||||
|
if((verlen <= 0) || ((len = krb_decode_time(s, 5, ×tr)) == 0))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
reppart->authtime = get_local_time(timestr);
|
||||||
|
verlen -= len;
|
||||||
|
xfree(timestr);
|
||||||
|
|
||||||
|
/* skip tag 6 (start time) */
|
||||||
|
if(verlen <= 0)
|
||||||
|
goto err;
|
||||||
|
len = krb_skip_contextual_tag(s, 6);
|
||||||
|
|
||||||
|
verlen -= len;
|
||||||
|
|
||||||
|
/* endtime[7] */
|
||||||
|
if((verlen <= 0) || ((len = krb_decode_time(s, 7, ×tr)) == 0))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
reppart->endtime = get_local_time(timestr);
|
||||||
|
verlen -= len;
|
||||||
|
xfree(timestr);
|
||||||
|
|
||||||
|
/* skip tag 8 (renew till) */
|
||||||
|
if(verlen <= 0)
|
||||||
|
goto err;
|
||||||
|
len = krb_skip_contextual_tag(s, 8);
|
||||||
|
|
||||||
|
verlen -= len;
|
||||||
|
|
||||||
|
/* realm[9] */
|
||||||
|
if((verlen <= 0) || ((len = krb_decode_string(s, 9, &(reppart->realm))) == 0))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
verlen -= len;
|
||||||
|
|
||||||
|
/* sname[10] */
|
||||||
|
if((verlen <= 0) || ((len = krb_decode_sname(s, 10, &(reppart->sname))) == 0))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
verlen -= len;
|
||||||
|
|
||||||
|
/* skip tag 11, 12 (tag 12 is supported enctypes) */
|
||||||
|
if(verlen <= 0)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
len = krb_skip_contextual_tag(s, 11);
|
||||||
|
len += krb_skip_contextual_tag(s, 12);
|
||||||
|
|
||||||
|
verlen -= len;
|
||||||
|
|
||||||
|
if(verlen != 0)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
stream_detach(s);
|
||||||
|
return reppart;
|
||||||
|
err:
|
||||||
|
krb_free_reppart(reppart);
|
||||||
|
xfree(reppart);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int krb_decode_tgtrep(STREAM* s, KrbTGTREP* krb_tgtrep)
|
||||||
|
{
|
||||||
|
uint8* bm;
|
||||||
|
int totlen, len, verlen;
|
||||||
|
totlen = 0;
|
||||||
|
stream_get_mark(s, bm);
|
||||||
|
|
||||||
|
/* sequence tag */
|
||||||
|
if(((len = krb_decode_sequence_tag(s, &verlen)) == 0))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
|
||||||
|
/* version no[0] */
|
||||||
|
if(((len = krb_decode_int(s, 0, (uint32*)&(krb_tgtrep->pvno))) == 0))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
verlen -= len;
|
||||||
|
|
||||||
|
/* msg type[1] */
|
||||||
|
if((verlen <= 0) || ((len = krb_decode_int(s, 1, (uint32*)&(krb_tgtrep->type))) == 0))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
verlen -= len;
|
||||||
|
|
||||||
|
/* ticket[2] */
|
||||||
|
if((verlen <= 0) || ((len = krb_decode_ticket(s, 2, &(krb_tgtrep->ticket))) == 0))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
totlen += len;
|
||||||
|
|
||||||
|
if(verlen != len)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
return totlen;
|
||||||
|
|
||||||
|
err:
|
||||||
|
stream_set_mark(s, bm);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
47
libfreerdp-auth/Kerberos/kerberos_decode.h
Normal file
47
libfreerdp-auth/Kerberos/kerberos_decode.h
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
/**
|
||||||
|
* FreeRDP: A Remote Desktop Protocol Client
|
||||||
|
* Kerberos Auth Protocol DER Decode
|
||||||
|
*
|
||||||
|
* 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 <freerdp/crypto/der.h>
|
||||||
|
|
||||||
|
#include "kerberos.h"
|
||||||
|
|
||||||
|
#ifndef __KRB_DECODE_H
|
||||||
|
#define __KRB_DECODE_H
|
||||||
|
|
||||||
|
int krb_decode_application_tag(STREAM* s, uint8 tag, int *length);
|
||||||
|
int krb_decode_sequence_tag(STREAM* s, int *length);
|
||||||
|
int krb_skip_contextual_tag(STREAM* s, uint8 tag);
|
||||||
|
int krb_decode_contextual_tag(STREAM* s, uint8 tag, int *length);
|
||||||
|
int krb_decode_integer(STREAM* s, uint32* value);
|
||||||
|
int krb_decode_time(STREAM* s, uint8 tag, char** str);
|
||||||
|
int krb_decode_int(STREAM* s, uint8 tag, uint32* result);
|
||||||
|
int krb_decode_flags(STREAM* s, uint8 tag, uint32* flags);
|
||||||
|
int krb_decode_string(STREAM* s, uint8 tag, char** str);
|
||||||
|
int krb_decode_octet_string(STREAM* s, uint8 tag, uint8** data, int* length);
|
||||||
|
int krb_decode_cname(STREAM* s, uint8 tag, char** str);
|
||||||
|
int krb_decode_sname(STREAM* s, uint8 tag, char** str);
|
||||||
|
int krb_decode_enckey(STREAM* s, KrbENCKey* key);
|
||||||
|
int krb_decode_encrypted_data(STREAM* s, KrbENCData* enc_data);
|
||||||
|
int krb_decode_ticket(STREAM* s, uint8 tag, Ticket* ticket);
|
||||||
|
int krb_decode_kdc_rep(STREAM* s, KrbKDCREP* kdc_rep, sint32 maxlen);
|
||||||
|
int krb_decode_krb_error(STREAM* s, KrbERROR* krb_err, sint32 maxlen);
|
||||||
|
ENCKDCREPPart* krb_decode_enc_reppart(rdpBlob* msg, uint8 apptag);
|
||||||
|
int krb_decode_tgtrep(STREAM* s, KrbTGTREP* krb_tgtrep);
|
||||||
|
|
||||||
|
#endif /* __KRB_DECODE_H */
|
389
libfreerdp-auth/Kerberos/kerberos_encode.c
Normal file
389
libfreerdp-auth/Kerberos/kerberos_encode.c
Normal file
@ -0,0 +1,389 @@
|
|||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
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, (char*[]){ cname, NULL });
|
||||||
|
stream_set_mark(s, bm);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
int krb_encode_sname(STREAM* s, uint8 tag, char* sname)
|
||||||
|
{
|
||||||
|
uint8* bm;
|
||||||
|
char* str;
|
||||||
|
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 = index(sname, '/') - sname;
|
||||||
|
str = (char*)xzalloc(tmp + 1);
|
||||||
|
strncpy(str, sname, tmp);
|
||||||
|
der_write_principal_name(s, NAME_TYPE_SERVICE, (char*[]){ str, (sname + tmp + 1), NULL });
|
||||||
|
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, curlen;
|
||||||
|
totlen = 0;
|
||||||
|
PAData** lpa_data;
|
||||||
|
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;
|
||||||
|
}
|
48
libfreerdp-auth/Kerberos/kerberos_encode.h
Normal file
48
libfreerdp-auth/Kerberos/kerberos_encode.h
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/**
|
||||||
|
* 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 <freerdp/crypto/der.h>
|
||||||
|
|
||||||
|
#include "kerberos.h"
|
||||||
|
|
||||||
|
#ifndef __KRB_ENCODE_H
|
||||||
|
#define __KRB_ENCODE_H
|
||||||
|
|
||||||
|
int krb_encode_sequence_tag(STREAM* s, uint32 len);
|
||||||
|
int krb_encode_contextual_tag(STREAM* s, uint8 tag, uint32 len);
|
||||||
|
int krb_encode_application_tag(STREAM* s, uint8 tag, uint32 len);
|
||||||
|
int krb_encode_recordmark(STREAM* s, uint32 len);
|
||||||
|
int krb_encode_cname(STREAM* s, uint8 tag, char* cname);
|
||||||
|
int krb_encode_sname(STREAM* s, uint8 tag, char* sname);
|
||||||
|
int krb_encode_uint8(STREAM* s, uint8 tag, uint8 val);
|
||||||
|
int krb_encode_integer(STREAM* s, uint8 tag, int val);
|
||||||
|
int krb_encode_options(STREAM* s, uint8 tag, uint32 options);
|
||||||
|
int krb_encode_string(STREAM* s, uint8 tag, char* str);
|
||||||
|
int krb_encode_time(STREAM* s, uint8 tag, char* strtime);
|
||||||
|
int krb_encode_octet_string(STREAM* s, uint8* string, uint32 len);
|
||||||
|
int krb_encode_padata(STREAM* s, PAData** pa_data);
|
||||||
|
int krb_encode_encrypted_data(STREAM* s, KrbENCData* enc_data);
|
||||||
|
int krb_encode_checksum(STREAM* s, rdpBlob* cksum, int cktype);
|
||||||
|
int krb_encode_authenticator(STREAM* s, Authenticator *krb_auth);
|
||||||
|
int krb_encode_ticket(STREAM* s, uint8 tag, Ticket* ticket);
|
||||||
|
int krb_encode_req_body(STREAM* s, KDCReqBody* req_body, int msgtype);
|
||||||
|
int krb_encode_apreq(STREAM* s, KrbAPREQ* krb_apreq);
|
||||||
|
int krb_encode_tgtreq(STREAM* s, KrbTGTREQ* krb_tgtreq);
|
||||||
|
|
||||||
|
#endif /* __KRB_ENCODE_H */
|
@ -45,3 +45,9 @@ void freerdp_blob_free(rdpBlob* blob)
|
|||||||
|
|
||||||
blob->length = 0;
|
blob->length = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void freerdp_blob_copy(rdpBlob* dstblob, rdpBlob* srcblob)
|
||||||
|
{
|
||||||
|
freerdp_blob_alloc(dstblob, srcblob->length);
|
||||||
|
memcpy(dstblob->data, srcblob->data, dstblob->length);
|
||||||
|
}
|
||||||
|
@ -125,3 +125,23 @@ char* xstrdup(const char* str)
|
|||||||
|
|
||||||
return mem;
|
return mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char* xstrtoup(const char* str)
|
||||||
|
{
|
||||||
|
char* out;
|
||||||
|
char* p;
|
||||||
|
int c;
|
||||||
|
out = xstrdup(str);
|
||||||
|
if(out != NULL)
|
||||||
|
{
|
||||||
|
p = out;
|
||||||
|
while(*p != '\0')
|
||||||
|
{
|
||||||
|
c = toupper((unsigned char)*p);
|
||||||
|
*p++ = (char)c;
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user