From: kouril Date: Fri, 5 Sep 2003 08:54:08 +0000 (+0000) Subject: Added wrapping calls (gss_init_sec_context_spnego() and gss_accept_sec_context_spnego... X-Git-Tag: v5.0-rc2~16 X-Git-Url: http://www.project-moonshot.org/gitweb/?p=mod_auth_kerb.cvs%2F.git;a=commitdiff_plain;h=36b6adb7e4924d6112814e6e369736cc0913821f Added wrapping calls (gss_init_sec_context_spnego() and gss_accept_sec_context_spnego()) for SPNEGO and krb5 gss-api --- diff --git a/spnegokrb5/Makefile b/spnegokrb5/Makefile new file mode 100644 index 0000000..85ae838 --- /dev/null +++ b/spnegokrb5/Makefile @@ -0,0 +1,27 @@ +KRB5_ROOT = /usr/heimdal + +CPPFLAGS = -I. -I$(KRB5_ROOT)/include +CFLAGS = -Wall -g + +gen_files = \ + asn1_MechType.c \ + asn1_MechTypeList.c \ + asn1_ContextFlags.c \ + asn1_NegTokenInit.c \ + asn1_NegTokenTarg.c + +asn1_files = \ + der_get.c \ + der_put.c \ + der_free.c \ + der_length.c \ + der_copy.c \ + timegm.c + +all: libspnegokrb5.a + +libspnegokrb5.a: $(gen_files:.c=.o) $(asn1_files:.c=.o) init_sec_context.o accept_sec_context.o + ar -rscu libspnegokrb5.a $^ + +clean: + $(RM) *.o core libspnegokrb5.a diff --git a/spnegokrb5/accept_sec_context.c b/spnegokrb5/accept_sec_context.c new file mode 100644 index 0000000..3735fae --- /dev/null +++ b/spnegokrb5/accept_sec_context.c @@ -0,0 +1,146 @@ +/* + * SPNEGO wrapper for Kerberos5 GSS-API + * kouril@ics.muni.cz, 2003 + */ +#include +#include + +#include +#include + +#define ALLOC(X) (X) = calloc(1, sizeof(*(X))) + +#define OID_cmp(o1, o2) \ + (((o1).length == (o2).length) && \ + (memcmp((o1).components, (o2).components,(int) (o1).length) == 0)) + +static int +create_reply(OM_uint32 major_status, oid *mech, gss_buffer_t mech_token, + gss_buffer_t output_token) +{ + NegTokenTarg targ_token; + unsigned char *buf = NULL; + size_t buf_size; + size_t len; + int ret; + + memset(&targ_token, 0, sizeof(targ_token)); + + ALLOC(targ_token.negResult); + if (targ_token.negResult == NULL) + return ENOMEM; + + *targ_token.negResult = (major_status == 0) ? accept_completed : accept_incomplete; + + ALLOC(targ_token.supportedMech); + if (targ_token.supportedMech == NULL) { + ret = ENOMEM; + goto end; + } + copy_MechType(mech, targ_token.supportedMech); + + if (mech_token->length > 0) { + ALLOC(targ_token.responseToken); + if (targ_token.responseToken == NULL) { + ret = ENOMEM; + goto end; + } + targ_token.responseToken->data = malloc(mech_token->length); + memcpy(targ_token.responseToken->data, mech_token->value, mech_token->length); + targ_token.responseToken->length = mech_token->length; + } + + ASN1_MALLOC_ENCODE(NegTokenTarg, buf, buf_size, &targ_token, &len, ret); + if (ret || buf_size != len) { + ret = EINVAL; + goto end; + } + + output_token->value = buf; + output_token->length = buf_size; + buf = NULL; + ret = 0; + +end: + free_NegTokenTarg(&targ_token); + + return ret; +} + +OM_uint32 gss_accept_sec_context_spnego + (OM_uint32 * minor_status, + gss_ctx_id_t * context_handle, + const gss_cred_id_t acceptor_cred_handle, + const gss_buffer_t input_token_buffer, + const gss_channel_bindings_t input_chan_bindings, + gss_name_t * src_name, + gss_OID * mech_type, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec, + gss_cred_id_t * delegated_cred_handle) +{ + NegTokenInit init_token; + OM_uint32 major_status; + gss_buffer_desc krb5_output_token = GSS_C_EMPTY_BUFFER; + gss_buffer_desc krb5_input_token = GSS_C_EMPTY_BUFFER; + size_t len; + int ret; + unsigned krb5_oid_array[] = + {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02}; + oid krb5_oid; + + krb5_oid.length = sizeof(krb5_oid_array); + krb5_oid.components = krb5_oid_array; + + memset(&init_token, 0, sizeof(init_token)); + + ret = decode_NegTokenInit(input_token_buffer->value, + input_token_buffer->length, + &init_token, &len); + if (ret) { + *minor_status = EINVAL; /* XXX */ + return GSS_S_DEFECTIVE_TOKEN; + } + + if (init_token.mechTypes == NULL || init_token.mechTypes->len == 0 || + OID_cmp(init_token.mechTypes->val[0], krb5_oid)) { + *minor_status = EINVAL; + ret = GSS_S_BAD_MECH; + goto end; + } + + if (init_token.mechToken) { + krb5_input_token.value = init_token.mechToken->data; + krb5_input_token.length = init_token.mechToken->length; + } + + major_status = gss_accept_sec_context(minor_status, + context_handle, + acceptor_cred_handle, + &krb5_input_token, + input_chan_bindings, + src_name, + mech_type, + &krb5_output_token, + ret_flags, + time_rec, + delegated_cred_handle); + if (GSS_ERROR(major_status)) { + ret = major_status; + goto end; + } + + ret = create_reply(major_status, &krb5_oid, &krb5_output_token, output_token); + if (ret) { + *minor_status = ret; + ret = GSS_S_FAILURE; + free(output_token); + } + +end: + free_NegTokenInit(&init_token); + + return ret; +} + diff --git a/spnegokrb5/asn1-common.h b/spnegokrb5/asn1-common.h new file mode 100644 index 0000000..6f470d7 --- /dev/null +++ b/spnegokrb5/asn1-common.h @@ -0,0 +1,21 @@ +/* $Id$ */ + +#include +#include + +#ifndef __asn1_common_definitions__ +#define __asn1_common_definitions__ + +typedef struct octet_string { + size_t length; + void *data; +} octet_string; + +typedef char *general_string; + +typedef struct oid { + size_t length; + unsigned *components; +} oid; + +#endif diff --git a/spnegokrb5/asn1_ContextFlags.c b/spnegokrb5/asn1_ContextFlags.c new file mode 100644 index 0000000..a5ff91b --- /dev/null +++ b/spnegokrb5/asn1_ContextFlags.c @@ -0,0 +1,142 @@ +/* Generated from spnego.asn1 */ +/* Do not edit */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BACK if (e) return e; p -= l; len -= l; ret += l + +int +encode_ContextFlags(unsigned char *p, size_t len, const ContextFlags *data, size_t *size) +{ +size_t ret = 0; +size_t l; +int i, e; + +i = 0; +{ +unsigned char c = 0; +*p-- = c; len--; ret++; +c = 0; +*p-- = c; len--; ret++; +c = 0; +*p-- = c; len--; ret++; +c = 0; +if(data->integFlag) c |= 1<<1; +if(data->confFlag) c |= 1<<2; +if(data->anonFlag) c |= 1<<3; +if(data->sequenceFlag) c |= 1<<4; +if(data->replayFlag) c |= 1<<5; +if(data->mutualFlag) c |= 1<<6; +if(data->delegFlag) c |= 1<<7; +*p-- = c; +*p-- = 0; +len -= 2; +ret += 2; +} + +e = der_put_length_and_tag (p, len, ret, UNIV, PRIM,UT_BitString, &l); +BACK; +*size = ret; +return 0; +} + +#define FORW if(e) goto fail; p += l; len -= l; ret += l + +int +decode_ContextFlags(const unsigned char *p, size_t len, ContextFlags *data, size_t *size) +{ +size_t ret = 0, reallen; +size_t l; +int e; + +memset(data, 0, sizeof(*data)); +reallen = 0; +e = der_match_tag_and_length (p, len, UNIV, PRIM, UT_BitString,&reallen, &l); +FORW; +if(len < reallen) +return ASN1_OVERRUN; +p++; +len--; +reallen--; +ret++; +data->delegFlag = (*p >> 7) & 1; +data->mutualFlag = (*p >> 6) & 1; +data->replayFlag = (*p >> 5) & 1; +data->sequenceFlag = (*p >> 4) & 1; +data->anonFlag = (*p >> 3) & 1; +data->confFlag = (*p >> 2) & 1; +data->integFlag = (*p >> 1) & 1; +p += reallen; len -= reallen; ret += reallen; +if(size) *size = ret; +return 0; +fail: +free_ContextFlags(data); +return e; +} + +void +free_ContextFlags(ContextFlags *data) +{ +} + +size_t +length_ContextFlags(const ContextFlags *data) +{ +size_t ret = 0; +ret += 7; +return ret; +} + +int +copy_ContextFlags(const ContextFlags *from, ContextFlags *to) +{ +*(to) = *(from); +return 0; +} + +unsigned ContextFlags2int(ContextFlags f) +{ +unsigned r = 0; +if(f.delegFlag) r |= (1U << 0); +if(f.mutualFlag) r |= (1U << 1); +if(f.replayFlag) r |= (1U << 2); +if(f.sequenceFlag) r |= (1U << 3); +if(f.anonFlag) r |= (1U << 4); +if(f.confFlag) r |= (1U << 5); +if(f.integFlag) r |= (1U << 6); +return r; +} + +ContextFlags int2ContextFlags(unsigned n) +{ + ContextFlags flags; + + flags.delegFlag = (n >> 0) & 1; + flags.mutualFlag = (n >> 1) & 1; + flags.replayFlag = (n >> 2) & 1; + flags.sequenceFlag = (n >> 3) & 1; + flags.anonFlag = (n >> 4) & 1; + flags.confFlag = (n >> 5) & 1; + flags.integFlag = (n >> 6) & 1; + return flags; +} + +struct units ContextFlags_units[] = { + {"integFlag", 1U << 6}, + {"confFlag", 1U << 5}, + {"anonFlag", 1U << 4}, + {"sequenceFlag", 1U << 3}, + {"replayFlag", 1U << 2}, + {"mutualFlag", 1U << 1}, + {"delegFlag", 1U << 0}, + {NULL, 0} +}; + diff --git a/spnegokrb5/asn1_MechType.c b/spnegokrb5/asn1_MechType.c new file mode 100644 index 0000000..4f8cc7b --- /dev/null +++ b/spnegokrb5/asn1_MechType.c @@ -0,0 +1,70 @@ +/* Generated from spnego.asn1 */ +/* Do not edit */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BACK if (e) return e; p -= l; len -= l; ret += l + +int +encode_MechType(unsigned char *p, size_t len, const MechType *data, size_t *size) +{ +size_t ret = 0; +size_t l; +int i, e; + +i = 0; +e = encode_oid(p, len, data, &l); +BACK; +*size = ret; +return 0; +} + +#define FORW if(e) goto fail; p += l; len -= l; ret += l + +int +decode_MechType(const unsigned char *p, size_t len, MechType *data, size_t *size) +{ +size_t ret = 0, reallen; +size_t l; +int e; + +memset(data, 0, sizeof(*data)); +reallen = 0; +e = decode_oid(p, len, data, &l); +FORW; +if(size) *size = ret; +return 0; +fail: +free_MechType(data); +return e; +} + +void +free_MechType(MechType *data) +{ +free_oid(data); +} + +size_t +length_MechType(const MechType *data) +{ +size_t ret = 0; +ret += length_oid(data); +return ret; +} + +int +copy_MechType(const MechType *from, MechType *to) +{ +if(copy_oid(from, to)) return ENOMEM; +return 0; +} + diff --git a/spnegokrb5/asn1_MechTypeList.c b/spnegokrb5/asn1_MechTypeList.c new file mode 100644 index 0000000..03b9fd9 --- /dev/null +++ b/spnegokrb5/asn1_MechTypeList.c @@ -0,0 +1,111 @@ +/* Generated from spnego.asn1 */ +/* Do not edit */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BACK if (e) return e; p -= l; len -= l; ret += l + +int +encode_MechTypeList(unsigned char *p, size_t len, const MechTypeList *data, size_t *size) +{ +size_t ret = 0; +size_t l; +int i, e; + +i = 0; +for(i = (data)->len - 1; i >= 0; --i) { +int oldret = ret; +ret = 0; +e = encode_MechType(p, len, &(data)->val[i], &l); +BACK; +ret += oldret; +} +e = der_put_length_and_tag (p, len, ret, UNIV, CONS, UT_Sequence, &l); +BACK; +*size = ret; +return 0; +} + +#define FORW if(e) goto fail; p += l; len -= l; ret += l + +int +decode_MechTypeList(const unsigned char *p, size_t len, MechTypeList *data, size_t *size) +{ +size_t ret = 0, reallen; +size_t l; +int e; + +memset(data, 0, sizeof(*data)); +reallen = 0; +e = der_match_tag_and_length (p, len, UNIV, CONS, UT_Sequence,&reallen, &l); +FORW; +if(len < reallen) +return ASN1_OVERRUN; +len = reallen; +{ +size_t origlen = len; +int oldret = ret; +ret = 0; +(data)->len = 0; +(data)->val = NULL; +while(ret < origlen) { +(data)->len++; +(data)->val = realloc((data)->val, sizeof(*((data)->val)) * (data)->len); +e = decode_MechType(p, len, &(data)->val[(data)->len-1], &l); +FORW; +len = origlen - ret; +} +ret += oldret; +} +if(size) *size = ret; +return 0; +fail: +free_MechTypeList(data); +return e; +} + +void +free_MechTypeList(MechTypeList *data) +{ +while((data)->len){ +free_MechType(&(data)->val[(data)->len-1]); +(data)->len--; +} +free((data)->val); +} + +size_t +length_MechTypeList(const MechTypeList *data) +{ +size_t ret = 0; +{ +int oldret = ret; +int i; +ret = 0; +for(i = (data)->len - 1; i >= 0; --i){ +ret += length_MechType(&(data)->val[i]); +} +ret += 1 + length_len(ret) + oldret; +} +return ret; +} + +int +copy_MechTypeList(const MechTypeList *from, MechTypeList *to) +{ +if(((to)->val = malloc((from)->len * sizeof(*(to)->val))) == NULL && (from)->len != 0) +return ENOMEM; +for((to)->len = 0; (to)->len < (from)->len; (to)->len++){ +if(copy_MechType(&(from)->val[(to)->len], &(to)->val[(to)->len])) return ENOMEM; +} +return 0; +} + diff --git a/spnegokrb5/asn1_NegTokenInit.c b/spnegokrb5/asn1_NegTokenInit.c new file mode 100644 index 0000000..49c835d --- /dev/null +++ b/spnegokrb5/asn1_NegTokenInit.c @@ -0,0 +1,293 @@ +/* Generated from spnego.asn1 */ +/* Do not edit */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BACK if (e) return e; p -= l; len -= l; ret += l + +int +encode_NegTokenInit(unsigned char *p, size_t len, const NegTokenInit *data, size_t *size) +{ +size_t ret = 0; +size_t l; +int i, e; + +i = 0; +if((data)->mechListMIC) +{ +int oldret = ret; +ret = 0; +e = encode_octet_string(p, len, (data)->mechListMIC, &l); +BACK; +e = der_put_length_and_tag (p, len, ret, CONTEXT, CONS, 3, &l); +BACK; +ret += oldret; +} +if((data)->mechToken) +{ +int oldret = ret; +ret = 0; +e = encode_octet_string(p, len, (data)->mechToken, &l); +BACK; +e = der_put_length_and_tag (p, len, ret, CONTEXT, CONS, 2, &l); +BACK; +ret += oldret; +} +if((data)->reqFlags) +{ +int oldret = ret; +ret = 0; +e = encode_ContextFlags(p, len, (data)->reqFlags, &l); +BACK; +e = der_put_length_and_tag (p, len, ret, CONTEXT, CONS, 1, &l); +BACK; +ret += oldret; +} +if((data)->mechTypes) +{ +int oldret = ret; +ret = 0; +e = encode_MechTypeList(p, len, (data)->mechTypes, &l); +BACK; +e = der_put_length_and_tag (p, len, ret, CONTEXT, CONS, 0, &l); +BACK; +ret += oldret; +} +e = der_put_length_and_tag (p, len, ret, UNIV, CONS, UT_Sequence, &l); +BACK; +*size = ret; +return 0; +} + +#define FORW if(e) goto fail; p += l; len -= l; ret += l + +int +decode_NegTokenInit(const unsigned char *p, size_t len, NegTokenInit *data, size_t *size) +{ +size_t ret = 0, reallen; +size_t l; +int e; + +memset(data, 0, sizeof(*data)); +reallen = 0; +e = der_match_tag_and_length (p, len, UNIV, CONS, UT_Sequence,&reallen, &l); +FORW; +{ +int dce_fix; +if((dce_fix = fix_dce(reallen, &len)) < 0) +return ASN1_BAD_FORMAT; +{ +size_t newlen, oldlen; + +e = der_match_tag (p, len, CONTEXT, CONS, 0, &l); +if (e) +(data)->mechTypes = NULL; +else { +p += l; +len -= l; +ret += l; +e = der_get_length (p, len, &newlen, &l); +FORW; +{ +int dce_fix; +oldlen = len; +if((dce_fix = fix_dce(newlen, &len)) < 0)return ASN1_BAD_FORMAT; +(data)->mechTypes = malloc(sizeof(*(data)->mechTypes)); +if((data)->mechTypes == NULL) return ENOMEM; +e = decode_MechTypeList(p, len, (data)->mechTypes, &l); +FORW; +if(dce_fix){ +e = der_match_tag_and_length (p, len, (Der_class)0, (Der_type)0, 0, &reallen, &l); +FORW; +}else +len = oldlen - newlen; +} +} +} +{ +size_t newlen, oldlen; + +e = der_match_tag (p, len, CONTEXT, CONS, 1, &l); +if (e) +(data)->reqFlags = NULL; +else { +p += l; +len -= l; +ret += l; +e = der_get_length (p, len, &newlen, &l); +FORW; +{ +int dce_fix; +oldlen = len; +if((dce_fix = fix_dce(newlen, &len)) < 0)return ASN1_BAD_FORMAT; +(data)->reqFlags = malloc(sizeof(*(data)->reqFlags)); +if((data)->reqFlags == NULL) return ENOMEM; +e = decode_ContextFlags(p, len, (data)->reqFlags, &l); +FORW; +if(dce_fix){ +e = der_match_tag_and_length (p, len, (Der_class)0, (Der_type)0, 0, &reallen, &l); +FORW; +}else +len = oldlen - newlen; +} +} +} +{ +size_t newlen, oldlen; + +e = der_match_tag (p, len, CONTEXT, CONS, 2, &l); +if (e) +(data)->mechToken = NULL; +else { +p += l; +len -= l; +ret += l; +e = der_get_length (p, len, &newlen, &l); +FORW; +{ +int dce_fix; +oldlen = len; +if((dce_fix = fix_dce(newlen, &len)) < 0)return ASN1_BAD_FORMAT; +(data)->mechToken = malloc(sizeof(*(data)->mechToken)); +if((data)->mechToken == NULL) return ENOMEM; +e = decode_octet_string(p, len, (data)->mechToken, &l); +FORW; +if(dce_fix){ +e = der_match_tag_and_length (p, len, (Der_class)0, (Der_type)0, 0, &reallen, &l); +FORW; +}else +len = oldlen - newlen; +} +} +} +{ +size_t newlen, oldlen; + +e = der_match_tag (p, len, CONTEXT, CONS, 3, &l); +if (e) +(data)->mechListMIC = NULL; +else { +p += l; +len -= l; +ret += l; +e = der_get_length (p, len, &newlen, &l); +FORW; +{ +int dce_fix; +oldlen = len; +if((dce_fix = fix_dce(newlen, &len)) < 0)return ASN1_BAD_FORMAT; +(data)->mechListMIC = malloc(sizeof(*(data)->mechListMIC)); +if((data)->mechListMIC == NULL) return ENOMEM; +e = decode_octet_string(p, len, (data)->mechListMIC, &l); +FORW; +if(dce_fix){ +e = der_match_tag_and_length (p, len, (Der_class)0, (Der_type)0, 0, &reallen, &l); +FORW; +}else +len = oldlen - newlen; +} +} +} +if(dce_fix){ +e = der_match_tag_and_length (p, len, (Der_class)0, (Der_type)0, 0, &reallen, &l); +FORW; +} +} +if(size) *size = ret; +return 0; +fail: +free_NegTokenInit(data); +return e; +} + +void +free_NegTokenInit(NegTokenInit *data) +{ +if((data)->mechTypes) { +free_MechTypeList((data)->mechTypes); +free((data)->mechTypes); +} +if((data)->reqFlags) { +free_ContextFlags((data)->reqFlags); +free((data)->reqFlags); +} +if((data)->mechToken) { +free_octet_string((data)->mechToken); +free((data)->mechToken); +} +if((data)->mechListMIC) { +free_octet_string((data)->mechListMIC); +free((data)->mechListMIC); +} +} + +size_t +length_NegTokenInit(const NegTokenInit *data) +{ +size_t ret = 0; +if((data)->mechTypes){ +int oldret = ret; +ret = 0; +ret += length_MechTypeList((data)->mechTypes); +ret += 1 + length_len(ret) + oldret; +} +if((data)->reqFlags){ +int oldret = ret; +ret = 0; +ret += length_ContextFlags((data)->reqFlags); +ret += 1 + length_len(ret) + oldret; +} +if((data)->mechToken){ +int oldret = ret; +ret = 0; +ret += length_octet_string((data)->mechToken); +ret += 1 + length_len(ret) + oldret; +} +if((data)->mechListMIC){ +int oldret = ret; +ret = 0; +ret += length_octet_string((data)->mechListMIC); +ret += 1 + length_len(ret) + oldret; +} +ret += 1 + length_len(ret); +return ret; +} + +int +copy_NegTokenInit(const NegTokenInit *from, NegTokenInit *to) +{ +if((from)->mechTypes) { +(to)->mechTypes = malloc(sizeof(*(to)->mechTypes)); +if((to)->mechTypes == NULL) return ENOMEM; +if(copy_MechTypeList((from)->mechTypes, (to)->mechTypes)) return ENOMEM; +}else +(to)->mechTypes = NULL; +if((from)->reqFlags) { +(to)->reqFlags = malloc(sizeof(*(to)->reqFlags)); +if((to)->reqFlags == NULL) return ENOMEM; +if(copy_ContextFlags((from)->reqFlags, (to)->reqFlags)) return ENOMEM; +}else +(to)->reqFlags = NULL; +if((from)->mechToken) { +(to)->mechToken = malloc(sizeof(*(to)->mechToken)); +if((to)->mechToken == NULL) return ENOMEM; +if(copy_octet_string((from)->mechToken, (to)->mechToken)) return ENOMEM; +}else +(to)->mechToken = NULL; +if((from)->mechListMIC) { +(to)->mechListMIC = malloc(sizeof(*(to)->mechListMIC)); +if((to)->mechListMIC == NULL) return ENOMEM; +if(copy_octet_string((from)->mechListMIC, (to)->mechListMIC)) return ENOMEM; +}else +(to)->mechListMIC = NULL; +return 0; +} + diff --git a/spnegokrb5/asn1_NegTokenTarg.c b/spnegokrb5/asn1_NegTokenTarg.c new file mode 100644 index 0000000..1729d86 --- /dev/null +++ b/spnegokrb5/asn1_NegTokenTarg.c @@ -0,0 +1,292 @@ +/* Generated from spnego.asn1 */ +/* Do not edit */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BACK if (e) return e; p -= l; len -= l; ret += l + +int +encode_NegTokenTarg(unsigned char *p, size_t len, const NegTokenTarg *data, size_t *size) +{ +size_t ret = 0; +size_t l; +int i, e; + +i = 0; +if((data)->mechListMIC) +{ +int oldret = ret; +ret = 0; +e = encode_octet_string(p, len, (data)->mechListMIC, &l); +BACK; +e = der_put_length_and_tag (p, len, ret, CONTEXT, CONS, 3, &l); +BACK; +ret += oldret; +} +if((data)->responseToken) +{ +int oldret = ret; +ret = 0; +e = encode_octet_string(p, len, (data)->responseToken, &l); +BACK; +e = der_put_length_and_tag (p, len, ret, CONTEXT, CONS, 2, &l); +BACK; +ret += oldret; +} +if((data)->supportedMech) +{ +int oldret = ret; +ret = 0; +e = encode_MechType(p, len, (data)->supportedMech, &l); +BACK; +e = der_put_length_and_tag (p, len, ret, CONTEXT, CONS, 1, &l); +BACK; +ret += oldret; +} +if((data)->negResult) +{ +int oldret = ret; +ret = 0; +e = encode_enumerated(p, len, (data)->negResult, &l); +BACK; +e = der_put_length_and_tag (p, len, ret, CONTEXT, CONS, 0, &l); +BACK; +ret += oldret; +} +e = der_put_length_and_tag (p, len, ret, UNIV, CONS, UT_Sequence, &l); +BACK; +*size = ret; +return 0; +} + +#define FORW if(e) goto fail; p += l; len -= l; ret += l + +int +decode_NegTokenTarg(const unsigned char *p, size_t len, NegTokenTarg *data, size_t *size) +{ +size_t ret = 0, reallen; +size_t l; +int e; + +memset(data, 0, sizeof(*data)); +reallen = 0; +e = der_match_tag_and_length (p, len, UNIV, CONS, UT_Sequence,&reallen, &l); +FORW; +{ +int dce_fix; +if((dce_fix = fix_dce(reallen, &len)) < 0) +return ASN1_BAD_FORMAT; +{ +size_t newlen, oldlen; + +e = der_match_tag (p, len, CONTEXT, CONS, 0, &l); +if (e) +(data)->negResult = NULL; +else { +p += l; +len -= l; +ret += l; +e = der_get_length (p, len, &newlen, &l); +FORW; +{ +int dce_fix; +oldlen = len; +if((dce_fix = fix_dce(newlen, &len)) < 0)return ASN1_BAD_FORMAT; +(data)->negResult = malloc(sizeof(*(data)->negResult)); +if((data)->negResult == NULL) return ENOMEM; +e = decode_enumerated(p, len, (data)->negResult, &l); +FORW; +if(dce_fix){ +e = der_match_tag_and_length (p, len, (Der_class)0, (Der_type)0, 0, &reallen, &l); +FORW; +}else +len = oldlen - newlen; +} +} +} +{ +size_t newlen, oldlen; + +e = der_match_tag (p, len, CONTEXT, CONS, 1, &l); +if (e) +(data)->supportedMech = NULL; +else { +p += l; +len -= l; +ret += l; +e = der_get_length (p, len, &newlen, &l); +FORW; +{ +int dce_fix; +oldlen = len; +if((dce_fix = fix_dce(newlen, &len)) < 0)return ASN1_BAD_FORMAT; +(data)->supportedMech = malloc(sizeof(*(data)->supportedMech)); +if((data)->supportedMech == NULL) return ENOMEM; +e = decode_MechType(p, len, (data)->supportedMech, &l); +FORW; +if(dce_fix){ +e = der_match_tag_and_length (p, len, (Der_class)0, (Der_type)0, 0, &reallen, &l); +FORW; +}else +len = oldlen - newlen; +} +} +} +{ +size_t newlen, oldlen; + +e = der_match_tag (p, len, CONTEXT, CONS, 2, &l); +if (e) +(data)->responseToken = NULL; +else { +p += l; +len -= l; +ret += l; +e = der_get_length (p, len, &newlen, &l); +FORW; +{ +int dce_fix; +oldlen = len; +if((dce_fix = fix_dce(newlen, &len)) < 0)return ASN1_BAD_FORMAT; +(data)->responseToken = malloc(sizeof(*(data)->responseToken)); +if((data)->responseToken == NULL) return ENOMEM; +e = decode_octet_string(p, len, (data)->responseToken, &l); +FORW; +if(dce_fix){ +e = der_match_tag_and_length (p, len, (Der_class)0, (Der_type)0, 0, &reallen, &l); +FORW; +}else +len = oldlen - newlen; +} +} +} +{ +size_t newlen, oldlen; + +e = der_match_tag (p, len, CONTEXT, CONS, 3, &l); +if (e) +(data)->mechListMIC = NULL; +else { +p += l; +len -= l; +ret += l; +e = der_get_length (p, len, &newlen, &l); +FORW; +{ +int dce_fix; +oldlen = len; +if((dce_fix = fix_dce(newlen, &len)) < 0)return ASN1_BAD_FORMAT; +(data)->mechListMIC = malloc(sizeof(*(data)->mechListMIC)); +if((data)->mechListMIC == NULL) return ENOMEM; +e = decode_octet_string(p, len, (data)->mechListMIC, &l); +FORW; +if(dce_fix){ +e = der_match_tag_and_length (p, len, (Der_class)0, (Der_type)0, 0, &reallen, &l); +FORW; +}else +len = oldlen - newlen; +} +} +} +if(dce_fix){ +e = der_match_tag_and_length (p, len, (Der_class)0, (Der_type)0, 0, &reallen, &l); +FORW; +} +} +if(size) *size = ret; +return 0; +fail: +free_NegTokenTarg(data); +return e; +} + +void +free_NegTokenTarg(NegTokenTarg *data) +{ +if((data)->negResult) { +free((data)->negResult); +} +if((data)->supportedMech) { +free_MechType((data)->supportedMech); +free((data)->supportedMech); +} +if((data)->responseToken) { +free_octet_string((data)->responseToken); +free((data)->responseToken); +} +if((data)->mechListMIC) { +free_octet_string((data)->mechListMIC); +free((data)->mechListMIC); +} +} + +size_t +length_NegTokenTarg(const NegTokenTarg *data) +{ +size_t ret = 0; +if((data)->negResult){ +int oldret = ret; +ret = 0; +ret += length_enumerated((data)->negResult); +ret += 1 + length_len(ret) + oldret; +} +if((data)->supportedMech){ +int oldret = ret; +ret = 0; +ret += length_MechType((data)->supportedMech); +ret += 1 + length_len(ret) + oldret; +} +if((data)->responseToken){ +int oldret = ret; +ret = 0; +ret += length_octet_string((data)->responseToken); +ret += 1 + length_len(ret) + oldret; +} +if((data)->mechListMIC){ +int oldret = ret; +ret = 0; +ret += length_octet_string((data)->mechListMIC); +ret += 1 + length_len(ret) + oldret; +} +ret += 1 + length_len(ret); +return ret; +} + +int +copy_NegTokenTarg(const NegTokenTarg *from, NegTokenTarg *to) +{ +if((from)->negResult) { +(to)->negResult = malloc(sizeof(*(to)->negResult)); +if((to)->negResult == NULL) return ENOMEM; +*((to)->negResult) = *((from)->negResult); +}else +(to)->negResult = NULL; +if((from)->supportedMech) { +(to)->supportedMech = malloc(sizeof(*(to)->supportedMech)); +if((to)->supportedMech == NULL) return ENOMEM; +if(copy_MechType((from)->supportedMech, (to)->supportedMech)) return ENOMEM; +}else +(to)->supportedMech = NULL; +if((from)->responseToken) { +(to)->responseToken = malloc(sizeof(*(to)->responseToken)); +if((to)->responseToken == NULL) return ENOMEM; +if(copy_octet_string((from)->responseToken, (to)->responseToken)) return ENOMEM; +}else +(to)->responseToken = NULL; +if((from)->mechListMIC) { +(to)->mechListMIC = malloc(sizeof(*(to)->mechListMIC)); +if((to)->mechListMIC == NULL) return ENOMEM; +if(copy_octet_string((from)->mechListMIC, (to)->mechListMIC)) return ENOMEM; +}else +(to)->mechListMIC = NULL; +return 0; +} + diff --git a/spnegokrb5/der.h b/spnegokrb5/der.h new file mode 100644 index 0000000..cd2a40a --- /dev/null +++ b/spnegokrb5/der.h @@ -0,0 +1,152 @@ +/* + * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef __DER_H__ +#define __DER_H__ + +#include + +typedef enum {UNIV = 0, APPL = 1, CONTEXT = 2 , PRIVATE = 3} Der_class; + +typedef enum {PRIM = 0, CONS = 1} Der_type; + +/* Universal tags */ + +enum { + UT_Boolean = 1, + UT_Integer = 2, + UT_BitString = 3, + UT_OctetString = 4, + UT_Null = 5, + UT_OID = 6, + UT_Enumerated = 10, + UT_Sequence = 16, + UT_Set = 17, + UT_PrintableString = 19, + UT_IA5String = 22, + UT_UTCTime = 23, + UT_GeneralizedTime = 24, + UT_VisibleString = 26, + UT_GeneralString = 27 +}; + +#define ASN1_INDEFINITE 0xdce0deed + +#ifndef HAVE_TIMEGM +time_t timegm (struct tm *); +#endif + +int time2generalizedtime (time_t t, octet_string *s); + +int der_get_int (const unsigned char *p, size_t len, int *ret, size_t *size); +int der_get_length (const unsigned char *p, size_t len, + size_t *val, size_t *size); +int der_get_general_string (const unsigned char *p, size_t len, + general_string *str, size_t *size); +int der_get_octet_string (const unsigned char *p, size_t len, + octet_string *data, size_t *size); +int der_get_oid (const unsigned char *p, size_t len, + oid *data, size_t *size); +int der_get_tag (const unsigned char *p, size_t len, + Der_class *class, Der_type *type, + int *tag, size_t *size); + +int der_match_tag (const unsigned char *p, size_t len, + Der_class class, Der_type type, + int tag, size_t *size); +int der_match_tag_and_length (const unsigned char *p, size_t len, + Der_class class, Der_type type, int tag, + size_t *length_ret, size_t *size); + +int decode_integer (const unsigned char*, size_t, int*, size_t*); +int decode_unsigned (const unsigned char*, size_t, unsigned*, size_t*); +int decode_enumerated (const unsigned char*, size_t, unsigned*, size_t*); +int decode_general_string (const unsigned char*, size_t, + general_string*, size_t*); +int decode_oid (const unsigned char *p, size_t len, + oid *k, size_t *size); +int decode_octet_string (const unsigned char*, size_t, octet_string*, size_t*); +int decode_generalized_time (const unsigned char*, size_t, time_t*, size_t*); + +int der_put_int (unsigned char *p, size_t len, int val, size_t*); +int der_put_length (unsigned char *p, size_t len, size_t val, size_t*); +int der_put_general_string (unsigned char *p, size_t len, + const general_string *str, size_t*); +int der_put_octet_string (unsigned char *p, size_t len, + const octet_string *data, size_t*); +int der_put_oid (unsigned char *p, size_t len, + const oid *data, size_t *size); +int der_put_tag (unsigned char *p, size_t len, Der_class class, Der_type type, + int tag, size_t*); +int der_put_length_and_tag (unsigned char*, size_t, size_t, + Der_class, Der_type, int, size_t*); + +int encode_integer (unsigned char *p, size_t len, + const int *data, size_t*); +int encode_unsigned (unsigned char *p, size_t len, + const unsigned *data, size_t*); +int encode_enumerated (unsigned char *p, size_t len, + const unsigned *data, size_t*); +int encode_general_string (unsigned char *p, size_t len, + const general_string *data, size_t*); +int encode_octet_string (unsigned char *p, size_t len, + const octet_string *k, size_t*); +int encode_oid (unsigned char *p, size_t len, + const oid *k, size_t*); +int encode_generalized_time (unsigned char *p, size_t len, + const time_t *t, size_t*); + +void free_integer (int *num); +void free_general_string (general_string *str); +void free_octet_string (octet_string *k); +void free_oid (oid *k); +void free_generalized_time (time_t *t); + +size_t length_len (size_t len); +size_t length_integer (const int *data); +size_t length_unsigned (const unsigned *data); +size_t length_enumerated (const unsigned *data); +size_t length_general_string (const general_string *data); +size_t length_octet_string (const octet_string *k); +size_t length_oid (const oid *k); +size_t length_generalized_time (const time_t *t); + +int copy_general_string (const general_string *from, general_string *to); +int copy_octet_string (const octet_string *from, octet_string *to); +int copy_oid (const oid *from, oid *to); + +int fix_dce(size_t reallen, size_t *len); + +#endif /* __DER_H__ */ diff --git a/spnegokrb5/der_copy.c b/spnegokrb5/der_copy.c new file mode 100644 index 0000000..f36800f --- /dev/null +++ b/spnegokrb5/der_copy.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "der_locl.h" + +#if 0 +RCSID("$Id$"); +#endif + +int +copy_general_string (const general_string *from, general_string *to) +{ + *to = strdup(*from); + if(*to == NULL) + return ENOMEM; + return 0; +} + +int +copy_octet_string (const octet_string *from, octet_string *to) +{ + to->length = from->length; + to->data = malloc(to->length); + if(to->length != 0 && to->data == NULL) + return ENOMEM; + memcpy(to->data, from->data, to->length); + return 0; +} + +int +copy_oid (const oid *from, oid *to) +{ + to->length = from->length; + to->components = malloc(to->length * sizeof(*to->components)); + if (to->length != 0 && to->components == NULL) + return ENOMEM; + memcpy(to->components, from->components, to->length); + return 0; +} diff --git a/spnegokrb5/der_free.c b/spnegokrb5/der_free.c new file mode 100644 index 0000000..7968cc0 --- /dev/null +++ b/spnegokrb5/der_free.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "der_locl.h" + +#if 0 +RCSID("$Id$"); +#endif + +void +free_general_string (general_string *str) +{ + free(*str); +} + +void +free_octet_string (octet_string *k) +{ + free(k->data); +} + +void +free_oid (oid *k) +{ + free(k->components); +} diff --git a/spnegokrb5/der_get.c b/spnegokrb5/der_get.c new file mode 100644 index 0000000..a8fbafe --- /dev/null +++ b/spnegokrb5/der_get.c @@ -0,0 +1,485 @@ +/* + * Copyright (c) 1997 - 2002 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "der_locl.h" + +#if 0 +RCSID("$Id$"); + +#include +#endif + +/* + * All decoding functions take a pointer `p' to first position in + * which to read, from the left, `len' which means the maximum number + * of characters we are able to read, `ret' were the value will be + * returned and `size' where the number of used bytes is stored. + * Either 0 or an error code is returned. + */ + +static int +der_get_unsigned (const unsigned char *p, size_t len, + unsigned *ret, size_t *size) +{ + unsigned val = 0; + size_t oldlen = len; + + while (len--) + val = val * 256 + *p++; + *ret = val; + if(size) *size = oldlen; + return 0; +} + +int +der_get_int (const unsigned char *p, size_t len, + int *ret, size_t *size) +{ + int val = 0; + size_t oldlen = len; + + if (len > 0) { + val = (signed char)*p++; + while (--len) + val = val * 256 + *p++; + } + *ret = val; + if(size) *size = oldlen; + return 0; +} + +int +der_get_length (const unsigned char *p, size_t len, + size_t *val, size_t *size) +{ + size_t v; + + if (len <= 0) + return ASN1_OVERRUN; + --len; + v = *p++; + if (v < 128) { + *val = v; + if(size) *size = 1; + } else { + int e; + size_t l; + unsigned tmp; + + if(v == 0x80){ + *val = ASN1_INDEFINITE; + if(size) *size = 1; + return 0; + } + v &= 0x7F; + if (len < v) + return ASN1_OVERRUN; + e = der_get_unsigned (p, v, &tmp, &l); + if(e) return e; + *val = tmp; + if(size) *size = l + 1; + } + return 0; +} + +int +der_get_general_string (const unsigned char *p, size_t len, + general_string *str, size_t *size) +{ + char *s; + + s = malloc (len + 1); + if (s == NULL) + return ENOMEM; + memcpy (s, p, len); + s[len] = '\0'; + *str = s; + if(size) *size = len; + return 0; +} + +int +der_get_octet_string (const unsigned char *p, size_t len, + octet_string *data, size_t *size) +{ + data->length = len; + data->data = malloc(len); + if (data->data == NULL && data->length != 0) + return ENOMEM; + memcpy (data->data, p, len); + if(size) *size = len; + return 0; +} + +int +der_get_oid (const unsigned char *p, size_t len, + oid *data, size_t *size) +{ + int n; + size_t oldlen = len; + + if (len < 1) + return ASN1_OVERRUN; + + data->components = malloc(len * sizeof(*data->components)); + if (data->components == NULL && len != 0) + return ENOMEM; + data->components[0] = (*p) / 40; + data->components[1] = (*p) % 40; + --len; + ++p; + for (n = 2; len > 0; ++n) { + unsigned u = 0; + + do { + --len; + u = u * 128 + (*p++ % 128); + } while (len > 0 && p[-1] & 0x80); + data->components[n] = u; + } + if (p[-1] & 0x80) { + free_oid (data); + return ASN1_OVERRUN; + } + data->length = n; + if (size) + *size = oldlen; + return 0; +} + +int +der_get_tag (const unsigned char *p, size_t len, + Der_class *class, Der_type *type, + int *tag, size_t *size) +{ + if (len < 1) + return ASN1_OVERRUN; + *class = (Der_class)(((*p) >> 6) & 0x03); + *type = (Der_type)(((*p) >> 5) & 0x01); + *tag = (*p) & 0x1F; + if(size) *size = 1; + return 0; +} + +int +der_match_tag (const unsigned char *p, size_t len, + Der_class class, Der_type type, + int tag, size_t *size) +{ + size_t l; + Der_class thisclass; + Der_type thistype; + int thistag; + int e; + + e = der_get_tag (p, len, &thisclass, &thistype, &thistag, &l); + if (e) return e; + if (class != thisclass || type != thistype) + return ASN1_BAD_ID; + if(tag > thistag) + return ASN1_MISPLACED_FIELD; + if(tag < thistag) + return ASN1_MISSING_FIELD; + if(size) *size = l; + return 0; +} + +int +der_match_tag_and_length (const unsigned char *p, size_t len, + Der_class class, Der_type type, int tag, + size_t *length_ret, size_t *size) +{ + size_t l, ret = 0; + int e; + + e = der_match_tag (p, len, class, type, tag, &l); + if (e) return e; + p += l; + len -= l; + ret += l; + e = der_get_length (p, len, length_ret, &l); + if (e) return e; + p += l; + len -= l; + ret += l; + if(size) *size = ret; + return 0; +} + +int +decode_integer (const unsigned char *p, size_t len, + int *num, size_t *size) +{ + size_t ret = 0; + size_t l, reallen; + int e; + + e = der_match_tag (p, len, UNIV, PRIM, UT_Integer, &l); + if (e) return e; + p += l; + len -= l; + ret += l; + e = der_get_length (p, len, &reallen, &l); + if (e) return e; + p += l; + len -= l; + ret += l; + if (reallen > len) + return ASN1_OVERRUN; + e = der_get_int (p, reallen, num, &l); + if (e) return e; + p += l; + len -= l; + ret += l; + if(size) *size = ret; + return 0; +} + +int +decode_unsigned (const unsigned char *p, size_t len, + unsigned *num, size_t *size) +{ + size_t ret = 0; + size_t l, reallen; + int e; + + e = der_match_tag (p, len, UNIV, PRIM, UT_Integer, &l); + if (e) return e; + p += l; + len -= l; + ret += l; + e = der_get_length (p, len, &reallen, &l); + if (e) return e; + p += l; + len -= l; + ret += l; + if (reallen > len) + return ASN1_OVERRUN; + e = der_get_unsigned (p, reallen, num, &l); + if (e) return e; + p += l; + len -= l; + ret += l; + if(size) *size = ret; + return 0; +} + +int +decode_enumerated (const unsigned char *p, size_t len, + unsigned *num, size_t *size) +{ + size_t ret = 0; + size_t l, reallen; + int e; + + e = der_match_tag (p, len, UNIV, PRIM, UT_Enumerated, &l); + if (e) return e; + p += l; + len -= l; + ret += l; + e = der_get_length (p, len, &reallen, &l); + if (e) return e; + p += l; + len -= l; + ret += l; + e = der_get_int (p, reallen, num, &l); + if (e) return e; + p += l; + len -= l; + ret += l; + if(size) *size = ret; + return 0; +} + +int +decode_general_string (const unsigned char *p, size_t len, + general_string *str, size_t *size) +{ + size_t ret = 0; + size_t l; + int e; + size_t slen; + + e = der_match_tag (p, len, UNIV, PRIM, UT_GeneralString, &l); + if (e) return e; + p += l; + len -= l; + ret += l; + + e = der_get_length (p, len, &slen, &l); + if (e) return e; + p += l; + len -= l; + ret += l; + if (len < slen) + return ASN1_OVERRUN; + + e = der_get_general_string (p, slen, str, &l); + if (e) return e; + p += l; + len -= l; + ret += l; + if(size) *size = ret; + return 0; +} + +int +decode_octet_string (const unsigned char *p, size_t len, + octet_string *k, size_t *size) +{ + size_t ret = 0; + size_t l; + int e; + size_t slen; + + e = der_match_tag (p, len, UNIV, PRIM, UT_OctetString, &l); + if (e) return e; + p += l; + len -= l; + ret += l; + + e = der_get_length (p, len, &slen, &l); + if (e) return e; + p += l; + len -= l; + ret += l; + if (len < slen) + return ASN1_OVERRUN; + + e = der_get_octet_string (p, slen, k, &l); + if (e) return e; + p += l; + len -= l; + ret += l; + if(size) *size = ret; + return 0; +} + +int +decode_oid (const unsigned char *p, size_t len, + oid *k, size_t *size) +{ + size_t ret = 0; + size_t l; + int e; + size_t slen; + + e = der_match_tag (p, len, UNIV, PRIM, UT_OID, &l); + if (e) return e; + p += l; + len -= l; + ret += l; + + e = der_get_length (p, len, &slen, &l); + if (e) return e; + p += l; + len -= l; + ret += l; + if (len < slen) + return ASN1_OVERRUN; + + e = der_get_oid (p, slen, k, &l); + if (e) return e; + p += l; + len -= l; + ret += l; + if(size) *size = ret; + return 0; +} + +static void +generalizedtime2time (const char *s, time_t *t) +{ + struct tm tm; + + memset(&tm, 0, sizeof(tm)); + sscanf (s, "%04d%02d%02d%02d%02d%02dZ", + &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, + &tm.tm_min, &tm.tm_sec); + tm.tm_year -= 1900; + tm.tm_mon -= 1; + *t = timegm (&tm); +} + +int +decode_generalized_time (const unsigned char *p, size_t len, + time_t *t, size_t *size) +{ + octet_string k; + char *times; + size_t ret = 0; + size_t l; + int e; + size_t slen; + + e = der_match_tag (p, len, UNIV, PRIM, UT_GeneralizedTime, &l); + if (e) return e; + p += l; + len -= l; + ret += l; + + e = der_get_length (p, len, &slen, &l); + if (e) return e; + p += l; + len -= l; + ret += l; + if (len < slen) + return ASN1_OVERRUN; + e = der_get_octet_string (p, slen, &k, &l); + if (e) return e; + p += l; + len -= l; + ret += l; + times = realloc(k.data, k.length + 1); + if (times == NULL){ + free(k.data); + return ENOMEM; + } + times[k.length] = 0; + generalizedtime2time (times, t); + free (times); + if(size) *size = ret; + return 0; +} + + +int +fix_dce(size_t reallen, size_t *len) +{ + if(reallen == ASN1_INDEFINITE) + return 1; + if(*len < reallen) + return -1; + *len = reallen; + return 0; +} diff --git a/spnegokrb5/der_length.c b/spnegokrb5/der_length.c new file mode 100644 index 0000000..e21e6eb --- /dev/null +++ b/spnegokrb5/der_length.c @@ -0,0 +1,156 @@ +/* + * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "der_locl.h" + +#if 0 +RCSID("$Id$"); +#endif + +static size_t +len_unsigned (unsigned val) +{ + size_t ret = 0; + + do { + ++ret; + val /= 256; + } while (val); + return ret; +} + +static size_t +len_int (int val) +{ + size_t ret = 0; + + if (val == 0) + return 1; + while (val > 255 || val < -255) { + ++ret; + val /= 256; + } + if (val != 0) { + ++ret; + if ((signed char)val != val) + ++ret; + val /= 256; + } + return ret; +} + +static size_t +len_oid (const oid *oid) +{ + size_t ret = 1; + int n; + + for (n = 2; n < oid->length; ++n) { + unsigned u = oid->components[n]; + + ++ret; + u /= 128; + while (u > 0) { + ++ret; + u /= 128; + } + } + return ret; +} + +size_t +length_len (size_t len) +{ + if (len < 128) + return 1; + else + return len_unsigned (len) + 1; +} + +size_t +length_integer (const int *data) +{ + size_t len = len_int (*data); + + return 1 + length_len(len) + len; +} + +size_t +length_unsigned (const unsigned *data) +{ + size_t len = len_unsigned (*data); + + return 1 + length_len(len) + len; +} + +size_t +length_enumerated (const unsigned *data) +{ + size_t len = len_int (*data); + + return 1 + length_len(len) + len; +} + +size_t +length_general_string (const general_string *data) +{ + char *str = *data; + size_t len = strlen(str); + return 1 + length_len(len) + len; +} + +size_t +length_octet_string (const octet_string *k) +{ + return 1 + length_len(k->length) + k->length; +} + +size_t +length_oid (const oid *k) +{ + size_t len = len_oid (k); + + return 1 + length_len(len) + len; +} + +size_t +length_generalized_time (const time_t *t) +{ + octet_string k; + size_t ret; + + time2generalizedtime (*t, &k); + ret = 1 + length_len(k.length) + k.length; + free (k.data); + return ret; +} diff --git a/spnegokrb5/der_locl.h b/spnegokrb5/der_locl.h new file mode 100644 index 0000000..ad5787c --- /dev/null +++ b/spnegokrb5/der_locl.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef __DER_LOCL_H__ +#define __DER_LOCL_H__ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#endif /* __DER_LOCL_H__ */ diff --git a/spnegokrb5/der_put.c b/spnegokrb5/der_put.c new file mode 100644 index 0000000..3dba944 --- /dev/null +++ b/spnegokrb5/der_put.c @@ -0,0 +1,423 @@ +/* + * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "der_locl.h" + +#if 0 +RCSID("$Id$"); +#endif + +/* + * All encoding functions take a pointer `p' to first position in + * which to write, from the right, `len' which means the maximum + * number of characters we are able to write. The function returns + * the number of characters written in `size' (if non-NULL). + * The return value is 0 or an error. + */ + +static int +der_put_unsigned (unsigned char *p, size_t len, unsigned val, size_t *size) +{ + unsigned char *base = p; + + if (val) { + while (len > 0 && val) { + *p-- = val % 256; + val /= 256; + --len; + } + if (val != 0) + return ASN1_OVERFLOW; + else { + *size = base - p; + return 0; + } + } else if (len < 1) + return ASN1_OVERFLOW; + else { + *p = 0; + *size = 1; + return 0; + } +} + +int +der_put_int (unsigned char *p, size_t len, int val, size_t *size) +{ + unsigned char *base = p; + + if(val >= 0) { + do { + if(len < 1) + return ASN1_OVERFLOW; + *p-- = val % 256; + len--; + val /= 256; + } while(val); + if(p[1] >= 128) { + if(len < 1) + return ASN1_OVERFLOW; + *p-- = 0; + len--; + } + } else { + val = ~val; + do { + if(len < 1) + return ASN1_OVERFLOW; + *p-- = ~(val % 256); + len--; + val /= 256; + } while(val); + if(p[1] < 128) { + if(len < 1) + return ASN1_OVERFLOW; + *p-- = 0xff; + len--; + } + } + *size = base - p; + return 0; +} + + +int +der_put_length (unsigned char *p, size_t len, size_t val, size_t *size) +{ + if (len < 1) + return ASN1_OVERFLOW; + if (val < 128) { + *p = val; + *size = 1; + return 0; + } else { + size_t l; + int e; + + e = der_put_unsigned (p, len - 1, val, &l); + if (e) + return e; + p -= l; + *p = 0x80 | l; + *size = l + 1; + return 0; + } +} + +int +der_put_general_string (unsigned char *p, size_t len, + const general_string *str, size_t *size) +{ + size_t slen = strlen(*str); + + if (len < slen) + return ASN1_OVERFLOW; + p -= slen; + len -= slen; + memcpy (p+1, *str, slen); + *size = slen; + return 0; +} + +int +der_put_octet_string (unsigned char *p, size_t len, + const octet_string *data, size_t *size) +{ + if (len < data->length) + return ASN1_OVERFLOW; + p -= data->length; + len -= data->length; + memcpy (p+1, data->data, data->length); + *size = data->length; + return 0; +} + +int +der_put_oid (unsigned char *p, size_t len, + const oid *data, size_t *size) +{ + unsigned char *base = p; + int n; + + for (n = data->length - 1; n >= 2; --n) { + unsigned u = data->components[n]; + + if (len < 1) + return ASN1_OVERFLOW; + *p-- = u % 128; + u /= 128; + --len; + while (u > 0) { + if (len < 1) + return ASN1_OVERFLOW; + *p-- = 128 + u % 128; + u /= 128; + --len; + } + } + if (len < 1) + return ASN1_OVERFLOW; + *p-- = 40 * data->components[0] + data->components[1]; + *size = base - p; + return 0; +} + +int +der_put_tag (unsigned char *p, size_t len, Der_class class, Der_type type, + int tag, size_t *size) +{ + if (len < 1) + return ASN1_OVERFLOW; + *p = (class << 6) | (type << 5) | tag; /* XXX */ + *size = 1; + return 0; +} + +int +der_put_length_and_tag (unsigned char *p, size_t len, size_t len_val, + Der_class class, Der_type type, int tag, size_t *size) +{ + size_t ret = 0; + size_t l; + int e; + + e = der_put_length (p, len, len_val, &l); + if(e) + return e; + p -= l; + len -= l; + ret += l; + e = der_put_tag (p, len, class, type, tag, &l); + if(e) + return e; + p -= l; + len -= l; + ret += l; + *size = ret; + return 0; +} + +int +encode_integer (unsigned char *p, size_t len, const int *data, size_t *size) +{ + int num = *data; + size_t ret = 0; + size_t l; + int e; + + e = der_put_int (p, len, num, &l); + if(e) + return e; + p -= l; + len -= l; + ret += l; + e = der_put_length_and_tag (p, len, l, UNIV, PRIM, UT_Integer, &l); + if (e) + return e; + p -= l; + len -= l; + ret += l; + *size = ret; + return 0; +} + +int +encode_unsigned (unsigned char *p, size_t len, const unsigned *data, + size_t *size) +{ + unsigned num = *data; + size_t ret = 0; + size_t l; + int e; + + e = der_put_unsigned (p, len, num, &l); + if(e) + return e; + p -= l; + len -= l; + ret += l; + e = der_put_length_and_tag (p, len, l, UNIV, PRIM, UT_Integer, &l); + if (e) + return e; + p -= l; + len -= l; + ret += l; + *size = ret; + return 0; +} + +int +encode_enumerated (unsigned char *p, size_t len, const unsigned *data, + size_t *size) +{ + unsigned num = *data; + size_t ret = 0; + size_t l; + int e; + + e = der_put_int (p, len, num, &l); + if(e) + return e; + p -= l; + len -= l; + ret += l; + e = der_put_length_and_tag (p, len, l, UNIV, PRIM, UT_Enumerated, &l); + if (e) + return e; + p -= l; + len -= l; + ret += l; + *size = ret; + return 0; +} + +int +encode_general_string (unsigned char *p, size_t len, + const general_string *data, size_t *size) +{ + size_t ret = 0; + size_t l; + int e; + + e = der_put_general_string (p, len, data, &l); + if (e) + return e; + p -= l; + len -= l; + ret += l; + e = der_put_length_and_tag (p, len, l, UNIV, PRIM, UT_GeneralString, &l); + if (e) + return e; + p -= l; + len -= l; + ret += l; + *size = ret; + return 0; +} + +int +encode_octet_string (unsigned char *p, size_t len, + const octet_string *k, size_t *size) +{ + size_t ret = 0; + size_t l; + int e; + + e = der_put_octet_string (p, len, k, &l); + if (e) + return e; + p -= l; + len -= l; + ret += l; + e = der_put_length_and_tag (p, len, l, UNIV, PRIM, UT_OctetString, &l); + if (e) + return e; + p -= l; + len -= l; + ret += l; + *size = ret; + return 0; +} + +int +encode_oid(unsigned char *p, size_t len, + const oid *k, size_t *size) +{ + size_t ret = 0; + size_t l; + int e; + + e = der_put_oid (p, len, k, &l); + if (e) + return e; + p -= l; + len -= l; + ret += l; + e = der_put_length_and_tag (p, len, l, UNIV, PRIM, UT_OID, &l); + if (e) + return e; + p -= l; + len -= l; + ret += l; + *size = ret; + return 0; +} + +int +time2generalizedtime (time_t t, octet_string *s) +{ + struct tm *tm; + size_t len; + + len = 15; + + s->data = malloc(len + 1); + if (s->data == NULL) + return ENOMEM; + s->length = len; + tm = gmtime (&t); + snprintf (s->data, len + 1, "%04d%02d%02d%02d%02d%02dZ", + tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + return 0; +} + +int +encode_generalized_time (unsigned char *p, size_t len, + const time_t *t, size_t *size) +{ + size_t ret = 0; + size_t l; + octet_string k; + int e; + + e = time2generalizedtime (*t, &k); + if (e) + return e; + e = der_put_octet_string (p, len, &k, &l); + free (k.data); + if (e) + return e; + p -= l; + len -= l; + ret += l; + e = der_put_length_and_tag (p, len, k.length, UNIV, PRIM, + UT_GeneralizedTime, &l); + if (e) + return e; + p -= l; + len -= l; + ret += l; + *size = ret; + return 0; +} diff --git a/spnegokrb5/init_sec_context.c b/spnegokrb5/init_sec_context.c new file mode 100644 index 0000000..a76a491 --- /dev/null +++ b/spnegokrb5/init_sec_context.c @@ -0,0 +1,152 @@ +/* + * SPNEGO wrapper for Kerberos5 GSS-API + * kouril@ics.muni.cz, 2003 + */ +#include +#include + +#include +#include + +#define ALLOC(X) (X) = calloc(1, sizeof(*(X))) + +static int +add_mech(MechTypeList *mech_list, oid *mech) +{ + MechType *tmp; + + tmp = realloc(mech_list->val, (mech_list->len + 1) * sizeof(*tmp)); + if (tmp == NULL) + return ENOMEM; + mech_list->val = tmp; + copy_MechType(mech, mech_list->val + mech_list->len); + mech_list->len++; + return 0; +} + +static int +set_context_flags(OM_uint32 req_flags, ContextFlags *flags) +{ + if (req_flags & GSS_C_DELEG_FLAG) + flags->delegFlag = 1; + if (req_flags & GSS_C_MUTUAL_FLAG) + flags->mutualFlag = 1; + if (req_flags & GSS_C_REPLAY_FLAG) + flags->replayFlag = 1; + if (req_flags & GSS_C_SEQUENCE_FLAG) + flags->sequenceFlag = 1; + if (req_flags & GSS_C_ANON_FLAG) + flags->anonFlag = 1; + if (req_flags & GSS_C_CONF_FLAG) + flags->confFlag = 1; + if (req_flags & GSS_C_INTEG_FLAG) + flags->integFlag = 1; + return 0; +} + +OM_uint32 gss_init_sec_context_spnego( + OM_uint32 * minor_status, + const gss_cred_id_t initiator_cred_handle, + gss_ctx_id_t * context_handle, + const gss_name_t target_name, + const gss_OID mech_type, + OM_uint32 req_flags, + OM_uint32 time_req, + const gss_channel_bindings_t input_chan_bindings, + const gss_buffer_t input_token, + gss_OID * actual_mech_type, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec) +{ + NegTokenInit token_init; + OM_uint32 major_status, minor_status2; + gss_buffer_desc krb5_output_token = GSS_C_EMPTY_BUFFER; + unsigned char *buf = NULL; + size_t buf_size; + size_t len; + int ret; + unsigned krb5_oid_array[] = + {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02}; + oid krb5_oid; + + memset(&token_init, 0, sizeof(token_init)); + + krb5_oid.length = sizeof(krb5_oid_array); + krb5_oid.components = krb5_oid_array; + + ALLOC(token_init.mechTypes); + if (token_init.mechTypes == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + ret = add_mech(token_init.mechTypes, &krb5_oid); + if (ret) { + *minor_status = ret; + ret = GSS_S_FAILURE; + goto end; + } + + ALLOC(token_init.reqFlags); + if (token_init.reqFlags == NULL) { + *minor_status = ENOMEM; + ret = GSS_S_FAILURE; + goto end; + } + set_context_flags(req_flags, token_init.reqFlags); + + major_status = gss_init_sec_context(minor_status, + initiator_cred_handle, + context_handle, + target_name, + (gss_OID) &krb5_oid, + req_flags, + time_req, + input_chan_bindings, + input_token, + actual_mech_type, + &krb5_output_token, + ret_flags, + time_rec); + if (GSS_ERROR(major_status)) { + ret = major_status; + goto end; + } + + if (krb5_output_token.length > 0) { + ALLOC(token_init.mechToken); + if (token_init.mechToken == NULL) { + *minor_status = ENOMEM; + ret = GSS_S_FAILURE; + goto end; + } + token_init.mechToken->data = krb5_output_token.value; + token_init.mechToken->length = krb5_output_token.length; + krb5_output_token.length = 0; /* don't free it later */ + } + + /* The MS implementation of SPNEGO seems to not like the mechListMIC field, + * so we omit it (it's optional anyway) */ + + ASN1_MALLOC_ENCODE(NegTokenInit, buf, buf_size, &token_init, &len, ret); + if (ret || buf_size != len) { + *minor_status = EINVAL; /* XXX */ + ret = GSS_S_FAILURE; + goto end; + } + + output_token->value = buf; + output_token->length = buf_size; + buf = NULL; + ret = major_status; + +end: + free_NegTokenInit(&token_init); + if (krb5_output_token.length > 0) + gss_release_buffer(&minor_status2, &krb5_output_token); + if (buf) + free(buf); + + return ret; +} diff --git a/spnegokrb5/spnego.asn1 b/spnegokrb5/spnego.asn1 new file mode 100644 index 0000000..3d010b4 --- /dev/null +++ b/spnegokrb5/spnego.asn1 @@ -0,0 +1,39 @@ +SPNEGO DEFINITIONS ::= +BEGIN + +-- NegotiationToken ::= CHOICE { +-- negTokenInit [0] NegTokenInit, +-- negTokenTarg [1] NegTokenTarg } + +MechType::= OBJECT IDENTIFIER + +MechTypeList ::= SEQUENCE OF MechType + +ContextFlags ::= BIT STRING { + delegFlag (0), + mutualFlag (1), + replayFlag (2), + sequenceFlag (3), + anonFlag (4), + confFlag (5), + integFlag (6) +} + +NegTokenInit ::= SEQUENCE { + mechTypes [0] MechTypeList OPTIONAL, + reqFlags [1] ContextFlags OPTIONAL, + mechToken [2] OCTET STRING OPTIONAL, + mechListMIC [3] OCTET STRING OPTIONAL + } + +NegTokenTarg ::= SEQUENCE { + negResult [0] ENUMERATED { + accept_completed (0), + accept_incomplete (1), + reject (2) } OPTIONAL, + supportedMech [1] MechType OPTIONAL, + responseToken [2] OCTET STRING OPTIONAL, + mechListMIC [3] OCTET STRING OPTIONAL +} + +END diff --git a/spnegokrb5/spnego_asn1.h b/spnegokrb5/spnego_asn1.h new file mode 100644 index 0000000..a58fe46 --- /dev/null +++ b/spnegokrb5/spnego_asn1.h @@ -0,0 +1,159 @@ +/* Generated from spnego.asn1 */ +/* Do not edit */ + +#ifndef __spnego_asn1_h__ +#define __spnego_asn1_h__ + +#include +#include + +#ifndef __asn1_common_definitions__ +#define __asn1_common_definitions__ + +typedef struct octet_string { + size_t length; + void *data; +} octet_string; + +typedef char *general_string; + +typedef struct oid { + size_t length; + unsigned *components; +} oid; + +#define ASN1_MALLOC_ENCODE(T, B, BL, S, L, R) \ + do { \ + (BL) = length_##T((S)); \ + (B) = malloc((BL)); \ + if((B) == NULL) { \ + (R) = ENOMEM; \ + } else { \ + (R) = encode_##T(((unsigned char*)(B)) + (BL) - 1, (BL), \ + (S), (L)); \ + if((R) != 0) { \ + free((B)); \ + (B) = NULL; \ + } \ + } \ + } while (0) + +#endif + +/* +MechType ::= OBJECT IDENTIFIER +*/ + +typedef oid MechType; + +int encode_MechType(unsigned char *, size_t, const MechType *, size_t *); +int decode_MechType(const unsigned char *, size_t, MechType *, size_t *); +void free_MechType (MechType *); +size_t length_MechType(const MechType *); +int copy_MechType (const MechType *, MechType *); + + +/* +MechTypeList ::= SEQUENCE OF MechType +*/ + +typedef struct MechTypeList { + unsigned int len; + MechType *val; +} MechTypeList; + +int encode_MechTypeList(unsigned char *, size_t, const MechTypeList *, size_t *); +int decode_MechTypeList(const unsigned char *, size_t, MechTypeList *, size_t *); +void free_MechTypeList (MechTypeList *); +size_t length_MechTypeList(const MechTypeList *); +int copy_MechTypeList (const MechTypeList *, MechTypeList *); + + +/* +ContextFlags ::= BIT STRING { + delegFlag(0), + mutualFlag(1), + replayFlag(2), + sequenceFlag(3), + anonFlag(4), + confFlag(5), + integFlag(6) +} +*/ + +typedef struct ContextFlags { + unsigned int delegFlag:1; + unsigned int mutualFlag:1; + unsigned int replayFlag:1; + unsigned int sequenceFlag:1; + unsigned int anonFlag:1; + unsigned int confFlag:1; + unsigned int integFlag:1; +} ContextFlags; + + +int encode_ContextFlags(unsigned char *, size_t, const ContextFlags *, size_t *); +int decode_ContextFlags(const unsigned char *, size_t, ContextFlags *, size_t *); +void free_ContextFlags (ContextFlags *); +size_t length_ContextFlags(const ContextFlags *); +int copy_ContextFlags (const ContextFlags *, ContextFlags *); +unsigned ContextFlags2int(ContextFlags); +ContextFlags int2ContextFlags(unsigned); +extern struct units ContextFlags_units[]; + +/* +NegTokenInit ::= SEQUENCE { + mechTypes[0] MechTypeList OPTIONAL, + reqFlags[1] ContextFlags OPTIONAL, + mechToken[2] OCTET STRING OPTIONAL, + mechListMIC[3] OCTET STRING OPTIONAL +} +*/ + +typedef struct NegTokenInit { + MechTypeList *mechTypes; + ContextFlags *reqFlags; + octet_string *mechToken; + octet_string *mechListMIC; +} NegTokenInit; + +int encode_NegTokenInit(unsigned char *, size_t, const NegTokenInit *, size_t *); +int decode_NegTokenInit(const unsigned char *, size_t, NegTokenInit *, size_t *); +void free_NegTokenInit (NegTokenInit *); +size_t length_NegTokenInit(const NegTokenInit *); +int copy_NegTokenInit (const NegTokenInit *, NegTokenInit *); + + +/* +NegTokenTarg ::= SEQUENCE { + negResult[0] ENUMERATED { + accept_completed(0), + accept_incomplete(1), + reject(2) + } OPTIONAL, + supportedMech[1] MechType OPTIONAL, + responseToken[2] OCTET STRING OPTIONAL, + mechListMIC[3] OCTET STRING OPTIONAL +} +*/ + +typedef struct NegTokenTarg { + enum { + accept_completed = 0, + accept_incomplete = 1, + reject = 2 + } *negResult; + + MechType *supportedMech; + octet_string *responseToken; + octet_string *mechListMIC; +} NegTokenTarg; + +int encode_NegTokenTarg(unsigned char *, size_t, const NegTokenTarg *, size_t *); +int decode_NegTokenTarg(const unsigned char *, size_t, NegTokenTarg *, size_t *); +void free_NegTokenTarg (NegTokenTarg *); +size_t length_NegTokenTarg(const NegTokenTarg *); +int copy_NegTokenTarg (const NegTokenTarg *, NegTokenTarg *); + + +#endif /* __spnego_asn1_h__ */ diff --git a/spnegokrb5/spnegokrb5.h b/spnegokrb5/spnegokrb5.h new file mode 100644 index 0000000..e8e7f7c --- /dev/null +++ b/spnegokrb5/spnegokrb5.h @@ -0,0 +1,42 @@ +#ifndef _SPNEGOKRB5_H_ +#define _SPNEGOKRB5_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +OM_uint32 gss_init_sec_context_spnego( + OM_uint32 * minor_status, + const gss_cred_id_t initiator_cred_handle, + gss_ctx_id_t * context_handle, + const gss_name_t target_name, + const gss_OID mech_type, + OM_uint32 req_flags, + OM_uint32 time_req, + const gss_channel_bindings_t input_chan_bindings, + const gss_buffer_t input_token, + gss_OID * actual_mech_type, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec); + +OM_uint32 gss_accept_sec_context_spnego + (OM_uint32 * minor_status, + gss_ctx_id_t * context_handle, + const gss_cred_id_t acceptor_cred_handle, + const gss_buffer_t input_token_buffer, + const gss_channel_bindings_t input_chan_bindings, + gss_name_t * src_name, + gss_OID * mech_type, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec, + gss_cred_id_t * delegated_cred_handle); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/spnegokrb5/timegm.c b/spnegokrb5/timegm.c new file mode 100644 index 0000000..ec21182 --- /dev/null +++ b/spnegokrb5/timegm.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) 1997 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "der_locl.h" + +#if 0 +RCSID("$Id$"); +#endif + +#ifndef HAVE_TIMEGM + +static int +is_leap(unsigned y) +{ + y += 1900; + return (y % 4) == 0 && ((y % 100) != 0 || (y % 400) == 0); +} + +time_t +timegm (struct tm *tm) +{ + static const unsigned ndays[2][12] ={ + {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, + {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}}; + time_t res = 0; + unsigned i; + + for (i = 70; i < tm->tm_year; ++i) + res += is_leap(i) ? 366 : 365; + + for (i = 0; i < tm->tm_mon; ++i) + res += ndays[is_leap(tm->tm_year)][i]; + res += tm->tm_mday - 1; + res *= 24; + res += tm->tm_hour; + res *= 60; + res += tm->tm_min; + res *= 60; + res += tm->tm_sec; + return res; +} + +#endif /* HAVE_TIMEGM */