STLIBOBJS= \
asn1_decode.o\
asn1_k_decode.o\
+ asn1_k_decode_fast.o\
+ asn1_k_decode_kdc.o\
+ asn1_k_decode_sam.o\
asn1_encode.o\
asn1_get.o\
asn1_make.o\
asn1buf.o\
krb5_decode.o\
+ krb5_decode_kdc.o\
krb5_encode.o\
asn1_k_encode.o\
ldap_key_seq.o\
SRCS= \
$(srcdir)/asn1_decode.c\
$(srcdir)/asn1_k_decode.c\
+ $(srcdir)/asn1_k_decode_fast.c\
+ $(srcdir)/asn1_k_decode_kdc.c\
+ $(srcdir)/asn1_k_decode_sam.c\
$(srcdir)/asn1_encode.c\
$(srcdir)/asn1_get.c\
$(srcdir)/asn1_make.c\
$(srcdir)/asn1buf.c\
$(srcdir)/krb5_decode.c\
+ $(srcdir)/krb5_decode_kdc.c\
$(srcdir)/krb5_encode.c\
$(srcdir)/asn1_k_encode.c\
$(srcdir)/ldap_key_seq.c\
OBJS= \
$(OUTPRE)asn1_decode.$(OBJEXT)\
$(OUTPRE)asn1_k_decode.$(OBJEXT)\
+ $(OUTPRE)asn1_k_decode_fast.$(OBJEXT)\
+ $(OUTPRE)asn1_k_decode_kdc.$(OBJEXT)\
+ $(OUTPRE)asn1_k_decode_sam.$(OBJEXT)\
$(OUTPRE)asn1_encode.$(OBJEXT)\
$(OUTPRE)asn1_get.$(OBJEXT)\
$(OUTPRE)asn1_make.$(OBJEXT)\
$(OUTPRE)asn1buf.$(OBJEXT)\
$(OUTPRE)krb5_decode.$(OBJEXT)\
+ $(OUTPRE)krb5_decode_kdc.$(OBJEXT)\
$(OUTPRE)krb5_encode.$(OBJEXT)\
$(OUTPRE)asn1_k_encode.$(OBJEXT)\
$(OUTPRE)ldap_key_seq.$(OBJEXT)\
*/
#include "asn1_k_decode.h"
+#include "asn1_k_decode_macros.h"
#include "asn1_decode.h"
#include "asn1_get.h"
#include "asn1_misc.h"
-#define clean_return(val) { retval = val; goto error_out; }
-
-/* Declare useful decoder variables. */
-#define setup() \
- asn1_error_code retval; \
- asn1_class asn1class; \
- asn1_construction construction; \
- asn1_tagnum tagnum; \
- unsigned int length, taglen
-
-#define unused_var(x) if (0) { x = 0; x = x - x; }
-
-/* This is used for prefetch of next tag in sequence. */
-#define next_tag() \
- { taginfo t2; \
- retval = asn1_get_tag_2(&subbuf, &t2); \
- if (retval) clean_return(retval); \
- /* Copy out to match previous functionality, until better integrated. */ \
- asn1class = t2.asn1class; \
- construction = t2.construction; \
- tagnum = t2.tagnum; \
- taglen = t2.length; \
- indef = t2.indef; \
- }
-
-static asn1_error_code
-asn1_get_eoc_tag (asn1buf *buf)
-{
- asn1_error_code retval;
- taginfo t;
-
- retval = asn1_get_tag_2(buf, &t);
- if (retval)
- return retval;
- if (t.asn1class != UNIVERSAL || t.tagnum || t.indef)
- return ASN1_MISSING_EOC;
- return 0;
-}
-
-/* Force check for EOC tag. */
-#define get_eoc() \
- { \
- retval = asn1_get_eoc_tag(&subbuf); \
- if (retval) clean_return(retval); \
- }
-
-#define alloc_field(var) \
- var = calloc(1, sizeof(*var)); \
- if ((var) == NULL) clean_return(ENOMEM)
-
-/*
- * Allocate a principal and initialize enough fields for
- * krb5_free_principal to have defined behavior.
- */
-#define alloc_principal(var) \
- alloc_field(var); \
- var->realm.data = NULL; \
- var->data = NULL
-
-/*
- * Allocate a data structure and initialize enough fields for
- * krb5_free_data to have defined behavior.
- */
-#define alloc_data(var) \
- alloc_field(var); \
- var->data = NULL
-
-/* Fetch an expected APPLICATION class tag and verify. */
-#define apptag(tagexpect) \
- { \
- taginfo t1; \
- retval = asn1_get_tag_2(buf, &t1); \
- if (retval) clean_return(retval); \
- if (t1.asn1class != APPLICATION || t1.construction != CONSTRUCTED || \
- t1.tagnum != (tagexpect)) clean_return(ASN1_BAD_ID); \
- /* Copy out to match previous functionality, until better integrated. */ \
- asn1class = t1.asn1class; \
- construction = t1.construction; \
- tagnum = t1.tagnum; \
- applen = t1.length; \
- }
-
-/**** normal fields ****/
-
-/*
- * get_field_body
- *
- * Get bare field. This also prefetches the next tag. The call to
- * get_eoc() assumes that any values fetched by this macro are
- * enclosed in a context-specific tag.
- */
-#define get_field_body(var, decoder) \
- retval = decoder(&subbuf, &(var)); \
- if (retval) clean_return(retval); \
- if (!taglen && indef) { get_eoc(); } \
- next_tag()
-
-/*
- * error_if_bad_tag
- *
- * Checks that the next tag is the expected one; returns with an error
- * if not.
- */
-#define error_if_bad_tag(tagexpect) \
- if (tagnum != (tagexpect)) { clean_return((tagnum < (tagexpect)) ? ASN1_MISPLACED_FIELD : ASN1_MISSING_FIELD); }
-
-/*
- * get_field
- *
- * Get field having an expected context specific tag. This assumes
- * that context-specific tags are monotonically increasing in its
- * verification of tag numbers.
- */
-#define get_field(var, tagexpect, decoder) \
- error_if_bad_tag(tagexpect); \
- if ((asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED) \
- && (tagnum || taglen || asn1class != UNIVERSAL)) \
- clean_return(ASN1_BAD_ID); \
- get_field_body(var,decoder)
-
-/*
- * opt_field
- *
- * Get an optional field with an expected context specific tag.
- * Assumes that OPTVAL will have the default value, thus failing to
- * distinguish between absent optional values and present optional
- * values that happen to have the value of OPTVAL.
- */
-#define opt_field(var, tagexpect, decoder, optvalue) \
- if (asn1buf_remains(&subbuf, seqindef)) { \
- if ((asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED) \
- && (tagnum || taglen || asn1class != UNIVERSAL)) \
- clean_return(ASN1_BAD_ID); \
- if (tagnum == (tagexpect)) { \
- get_field_body(var, decoder); \
- } else var = optvalue; \
- }
-
-/**** fields w/ length ****/
-
-/* similar to get_field_body */
-#define get_lenfield_body(len, var, decoder) \
- retval = decoder(&subbuf, &(len), &(var)); \
- if (retval) clean_return(retval); \
- if (!taglen && indef) { get_eoc(); } \
- next_tag()
-
-/* similar to get_field_body */
-#define get_lenfield(len, var, tagexpect, decoder) \
- error_if_bad_tag(tagexpect); \
- if ((asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED) \
- && (tagnum || taglen || asn1class != UNIVERSAL)) \
- clean_return(ASN1_BAD_ID); \
- get_lenfield_body(len, var, decoder)
-
-/* similar to opt_field */
-#define opt_lenfield(len, var, tagexpect, decoder) \
- if (tagnum == (tagexpect)) { \
- get_lenfield_body(len, var, decoder); \
- } else { len = 0; var = 0; }
-
-/*
- * Deal with implicitly tagged fields
- */
-#define get_implicit_octet_string(len, var, tagexpect) \
- if (tagnum != (tagexpect)) clean_return(ASN1_MISSING_FIELD); \
- if (asn1class != CONTEXT_SPECIFIC || construction != PRIMITIVE) \
- clean_return(ASN1_BAD_ID); \
- retval = asn1buf_remove_octetstring(&subbuf, taglen, &(var)); \
- if (retval) clean_return(retval); \
- (len) = taglen; \
- next_tag()
-
-#define opt_implicit_octet_string(len, var, tagexpect) \
- if (tagnum == (tagexpect)) { \
- if (asn1class != CONTEXT_SPECIFIC || construction != PRIMITIVE) \
- clean_return(ASN1_BAD_ID); \
- retval = asn1buf_remove_octetstring(&subbuf, taglen, &(var)); \
- if (retval) clean_return(retval); \
- (len) = taglen; \
- next_tag(); \
- } else { (len) = 0; (var) = NULL; }
-
-/*
- * begin_structure
- *
- * Declares some variables for decoding SEQUENCE types. This is meant
- * to be called in an inner block that ends with a call to
- * end_structure().
- */
-#define begin_structure() \
- asn1buf subbuf; \
- int seqindef; \
- int indef; \
- retval = asn1_get_sequence(buf, &length, &seqindef); \
- if (retval) clean_return(retval); \
- retval = asn1buf_imbed(&subbuf, buf, length, seqindef); \
- if (retval) clean_return(retval); \
- next_tag()
-
-/*
- * This is used for structures which have no tagging.
- * It is the same as begin_structure() except next_tag()
- * is not called.
- */
-#define begin_structure_no_tag() \
- asn1buf subbuf; \
- int seqindef; \
- int indef; \
- retval = asn1_get_sequence(buf, &length, &seqindef); \
- if (retval) clean_return(retval); \
- retval = asn1buf_imbed(&subbuf, buf, length, seqindef); \
- if (retval) clean_return(retval)
-
-/* skip trailing garbage */
-#define end_structure() \
- retval = asn1buf_sync(buf, &subbuf, asn1class, tagnum, \
- length, indef, seqindef); \
- if (retval) clean_return(retval)
-
-/*
- * begin_choice
- *
- * Declares some variables for decoding CHOICE types. This is meant
- * to be called in an inner block that ends with a call to
- * end_choice().
- */
-#define begin_choice() \
- asn1buf subbuf; \
- int seqindef; \
- int indef; \
- taginfo t; \
- retval = asn1_get_tag_2(buf, &t); \
- if (retval) clean_return(retval); \
- tagnum = t.tagnum; \
- taglen = t.length; \
- indef = t.indef; \
- length = t.length; \
- seqindef = t.indef; \
- asn1class = t.asn1class; \
- construction = t.construction; \
- retval = asn1buf_imbed(&subbuf, buf, length, seqindef); \
- if (retval) clean_return(retval)
-
-/* skip trailing garbage */
-#define end_choice() \
- length -= t.length; \
- retval = asn1buf_sync(buf, &subbuf, t.asn1class, t.tagnum, \
- length, t.indef, seqindef); \
- if (retval) clean_return(retval)
-
-/*
- * sequence_of
- *
- * Declares some variables for decoding SEQUENCE OF types. This is
- * meant to be called in an inner block that ends with a call to
- * end_sequence_of().
- */
-#define sequence_of(buf) \
- unsigned int length, taglen; \
- asn1_class asn1class; \
- asn1_construction construction; \
- asn1_tagnum tagnum; \
- int indef; \
- sequence_of_common(buf)
-
-/*
- * sequence_of_no_tagvars
- *
- * This is meant for use inside decoder functions that have an outer
- * sequence structure and thus declares variables of different names
- * than does sequence_of() to avoid shadowing.
- */
-#define sequence_of_no_tagvars(buf) \
- sequence_of_common(buf)
-
-/*
- * sequence_of_common
- *
- * Fetches the outer SEQUENCE OF length info into {length,seqofindef}
- * and imbeds an inner buffer seqbuf. Unlike begin_structure(), it
- * does not prefetch the next tag.
- */
-#define sequence_of_common(buf) \
- asn1buf seqbuf; \
- int seqofindef; \
- retval = asn1_get_sequence(buf, &length, &seqofindef); \
- if (retval) clean_return(retval); \
- retval = asn1buf_imbed(&seqbuf, buf, length, seqofindef); \
- if (retval) clean_return(retval)
-
-/*
- * end_sequence_of
- *
- * Attempts to fetch an EOC tag, if any, and to sync over trailing
- * garbage, if any.
- */
-#define end_sequence_of(buf) \
- { \
- taginfo t4; \
- retval = asn1_get_tag_2(&seqbuf, &t4); \
- if (retval) clean_return(retval); \
- /* Copy out to match previous functionality, until better integrated. */ \
- asn1class = t4.asn1class; \
- construction = t4.construction; \
- tagnum = t4.tagnum; \
- taglen = t4.length; \
- indef = t4.indef; \
- } \
- retval = asn1buf_sync(buf, &seqbuf, asn1class, tagnum, \
- length, indef, seqofindef); \
- if (retval) clean_return(retval);
-
-/*
- * end_sequence_of_no_tagvars
- *
- * Like end_sequence_of(), but uses the different (non-shadowing)
- * variable names.
- */
-static asn1_error_code
-end_sequence_of_no_tagvars_helper(asn1buf *buf, asn1buf *seqbufp,
- int seqofindef)
-{
- taginfo t;
- asn1_error_code retval;
-
- retval = asn1_get_tag_2(seqbufp, &t);
- if (retval)
- return retval;
- retval = asn1buf_sync(buf, seqbufp, t.asn1class, t.tagnum,
- t.length, t.indef, seqofindef);
- return retval;
-}
-#define end_sequence_of_no_tagvars(buf) \
- retval = end_sequence_of_no_tagvars_helper(buf, &seqbuf, seqofindef); \
- if (retval) clean_return(retval)
-
-/*
- * Function body for a pointer decoder, which allocates a pointer
- * field and invokes a structure decoder to fill it in. Pointer
- * decoders always fill in their output parameters with NULL (on
- * error) or a valid constructed structure, making cleanup easier on
- * callers.
- */
-#define decode_ptr(type, structure_decoder) \
- type val; \
- asn1_error_code retval; \
- \
- *valptr = NULL; \
- val = calloc(1, sizeof(*val)); \
- if (!val) \
- return ENOMEM; \
- retval = structure_decoder(buf, val); \
- if (retval) { \
- free(val); \
- return retval; \
- } \
- *valptr = val; \
- return 0;
+integer_convert(asn1_decode_int,int)
+integer_convert(asn1_decode_int32,krb5_int32)
+integer_convert(asn1_decode_kvno,krb5_kvno)
+integer_convert(asn1_decode_enctype,krb5_enctype)
+integer_convert(asn1_decode_cksumtype,krb5_cksumtype)
+integer_convert(asn1_decode_octet,krb5_octet)
+integer_convert(asn1_decode_addrtype,krb5_addrtype)
+integer_convert(asn1_decode_authdatatype,krb5_authdatatype)
+unsigned_integer_convert(asn1_decode_ui_2,krb5_ui_2)
+unsigned_integer_convert(asn1_decode_ui_4,krb5_ui_4)
/* scalars */
asn1_error_code
return 0;
}
-#define integer_convert(fname,ktype) \
- asn1_error_code fname(asn1buf * buf, ktype * val) \
- { \
- asn1_error_code retval; \
- long n; \
- retval = asn1_decode_integer(buf,&n); \
- if (retval) return retval; \
- *val = (ktype)n; \
- return 0; \
- }
-#define unsigned_integer_convert(fname,ktype) \
- asn1_error_code fname(asn1buf * buf, ktype * val) \
- { \
- asn1_error_code retval; \
- unsigned long n; \
- retval = asn1_decode_unsigned_integer(buf,&n); \
- if (retval) return retval; \
- *val = (ktype)n; \
- return 0; \
- }
-integer_convert(asn1_decode_int,int)
-integer_convert(asn1_decode_int32,krb5_int32)
-integer_convert(asn1_decode_kvno,krb5_kvno)
-integer_convert(asn1_decode_enctype,krb5_enctype)
-integer_convert(asn1_decode_cksumtype,krb5_cksumtype)
-integer_convert(asn1_decode_octet,krb5_octet)
-integer_convert(asn1_decode_addrtype,krb5_addrtype)
-integer_convert(asn1_decode_authdatatype,krb5_authdatatype)
-unsigned_integer_convert(asn1_decode_ui_2,krb5_ui_2)
-unsigned_integer_convert(asn1_decode_ui_4,krb5_ui_4)
-
asn1_error_code
asn1_decode_seqnum(asn1buf *buf, krb5_ui_4 *val)
{
decode_ptr(krb5_ticket *, asn1_decode_ticket);
}
-asn1_error_code
-asn1_decode_kdc_req(asn1buf *buf, krb5_kdc_req *val)
-{
- setup();
- val->padata = NULL;
- { begin_structure();
- { krb5_kvno kvno;
- get_field(kvno,1,asn1_decode_kvno);
- if (kvno != KVNO) clean_return(KRB5KDC_ERR_BAD_PVNO); }
- get_field(val->msg_type,2,asn1_decode_msgtype);
- opt_field(val->padata,3,asn1_decode_sequence_of_pa_data,NULL);
- get_field(*val,4,asn1_decode_kdc_req_body);
- end_structure();
- val->magic = KV5M_KDC_REQ;
- }
- return 0;
-error_out:
- krb5_free_pa_data(NULL, val->padata);
- val->padata = NULL;
- return retval;
-}
-
-asn1_error_code
-asn1_decode_kdc_req_body(asn1buf *buf, krb5_kdc_req *val)
-{
- setup();
- val->client = NULL;
- val->server = NULL;
- val->ktype = NULL;
- val->addresses = NULL;
- val->authorization_data.ciphertext.data = NULL;
- val->unenc_authdata = NULL;
- val->second_ticket = NULL;
- {
- krb5_principal psave;
- begin_structure();
- get_field(val->kdc_options,0,asn1_decode_kdc_options);
- if (tagnum == 1) { alloc_principal(val->client); }
- opt_field(val->client,1,asn1_decode_principal_name,NULL);
- alloc_principal(val->server);
- get_field(val->server,2,asn1_decode_realm);
- if (val->client != NULL) {
- retval = asn1_krb5_realm_copy(val->client,val->server);
- if (retval) clean_return(retval); }
-
- /* If opt_field server is missing, memory reference to server is
- lost and results in memory leak */
- psave = val->server;
- opt_field(val->server,3,asn1_decode_principal_name,NULL);
- if (val->server == NULL) {
- if (psave->realm.data) {
- free(psave->realm.data);
- psave->realm.data = NULL;
- psave->realm.length=0;
- }
- free(psave);
- }
- opt_field(val->from,4,asn1_decode_kerberos_time,0);
- get_field(val->till,5,asn1_decode_kerberos_time);
- opt_field(val->rtime,6,asn1_decode_kerberos_time,0);
- get_field(val->nonce,7,asn1_decode_int32);
- get_lenfield(val->nktypes,val->ktype,8,asn1_decode_sequence_of_enctype);
- opt_field(val->addresses,9,asn1_decode_host_addresses,0);
- if (tagnum == 10) {
- get_field(val->authorization_data,10,asn1_decode_encrypted_data); }
- else {
- val->authorization_data.magic = KV5M_ENC_DATA;
- val->authorization_data.enctype = 0;
- val->authorization_data.kvno = 0;
- val->authorization_data.ciphertext.data = NULL;
- val->authorization_data.ciphertext.length = 0;
- }
- opt_field(val->second_ticket,11,asn1_decode_sequence_of_ticket,NULL);
- end_structure();
- val->magic = KV5M_KDC_REQ;
- }
- return 0;
-error_out:
- krb5_free_principal(NULL, val->client);
- krb5_free_principal(NULL, val->server);
- free(val->ktype);
- krb5_free_addresses(NULL, val->addresses);
- krb5_free_data_contents(NULL, &val->authorization_data.ciphertext);
- krb5_free_tickets(NULL, val->second_ticket);
- val->client = NULL;
- val->server = NULL;
- val->ktype = NULL;
- val->addresses = NULL;
- val->unenc_authdata = NULL;
- val->second_ticket = NULL;
- return retval;
-}
-
asn1_error_code
asn1_decode_krb_safe_body(asn1buf *buf, krb5_safe *val)
{
decode_array_body(passwd_phrase_element,asn1_decode_passwdsequence_ptr,
krb5_free_passwd_phrase_element);
}
-
-asn1_error_code
-asn1_decode_sam_flags(asn1buf *buf, krb5_flags *val)
-{
- return asn1_decode_krb5_flags(buf,val);
-}
-
-#define opt_string(val,n,fn) opt_lenfield((val).length,(val).data,n,fn)
-#define opt_cksum(var,tagexpect,decoder) \
- if (tagnum == (tagexpect)) { \
- get_field_body(var,decoder); } \
- else var.length = 0
-
-asn1_error_code
-asn1_decode_sam_challenge(asn1buf *buf, krb5_sam_challenge *val)
-{
- setup();
- val->sam_type_name.data = NULL;
- val->sam_track_id.data = NULL;
- val->sam_challenge_label.data = NULL;
- val->sam_response_prompt.data = NULL;
- val->sam_pk_for_sad.data = NULL;
- val->sam_cksum.contents = NULL;
- { begin_structure();
- get_field(val->sam_type,0,asn1_decode_int32);
- get_field(val->sam_flags,1,asn1_decode_sam_flags);
- opt_string(val->sam_type_name,2,asn1_decode_charstring);
- opt_string(val->sam_track_id,3,asn1_decode_charstring);
- opt_string(val->sam_challenge_label,4,asn1_decode_charstring);
- opt_string(val->sam_challenge,5,asn1_decode_charstring);
- opt_string(val->sam_response_prompt,6,asn1_decode_charstring);
- opt_string(val->sam_pk_for_sad,7,asn1_decode_charstring);
- opt_field(val->sam_nonce,8,asn1_decode_int32,0);
- opt_cksum(val->sam_cksum,9,asn1_decode_checksum);
- end_structure();
- val->magic = KV5M_SAM_CHALLENGE;
- }
- return 0;
-error_out:
- krb5_free_sam_challenge_contents(NULL, val);
- return retval;
-}
-asn1_error_code
-asn1_decode_sam_challenge_2(asn1buf *buf, krb5_sam_challenge_2 *val)
-{
- krb5_checksum **cksump;
- setup();
- val->sam_challenge_2_body.data = NULL;
- val->sam_cksum = NULL;
- { char *save, *end;
- size_t alloclen;
- begin_structure();
- if (tagnum != 0) clean_return(ASN1_MISSING_FIELD);
- if (asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED)
- clean_return(ASN1_BAD_ID);
- save = subbuf.next;
- { sequence_of_no_tagvars(&subbuf);
- end_sequence_of_no_tagvars(&subbuf);
- }
- end = subbuf.next;
- alloclen = end - save;
- val->sam_challenge_2_body.data = malloc(alloclen);
- if (!val->sam_challenge_2_body.data)
- clean_return(ENOMEM);
- val->sam_challenge_2_body.length = alloclen;
- memcpy(val->sam_challenge_2_body.data, save, alloclen);
- next_tag();
- get_field(val->sam_cksum, 1, asn1_decode_sequence_of_checksum);
- end_structure();
- }
- return 0;
-error_out:
- krb5_free_data_contents(NULL, &val->sam_challenge_2_body);
- if (val->sam_cksum) {
- for (cksump = val->sam_cksum; *cksump; cksump++)
- krb5_free_checksum(NULL, *cksump);
- free(val->sam_cksum);
- val->sam_cksum = NULL;
- }
- return retval;
-}
-asn1_error_code
-asn1_decode_sam_challenge_2_body(asn1buf *buf, krb5_sam_challenge_2_body *val)
-{
- setup();
- val->sam_type_name.data = NULL;
- val->sam_track_id.data = NULL;
- val->sam_challenge_label.data = NULL;
- val->sam_challenge.data = NULL;
- val->sam_response_prompt.data = NULL;
- val->sam_pk_for_sad.data = NULL;
- { begin_structure();
- get_field(val->sam_type,0,asn1_decode_int32);
- get_field(val->sam_flags,1,asn1_decode_sam_flags);
- opt_string(val->sam_type_name,2,asn1_decode_charstring);
- opt_string(val->sam_track_id,3,asn1_decode_charstring);
- opt_string(val->sam_challenge_label,4,asn1_decode_charstring);
- opt_string(val->sam_challenge,5,asn1_decode_charstring);
- opt_string(val->sam_response_prompt,6,asn1_decode_charstring);
- opt_string(val->sam_pk_for_sad,7,asn1_decode_charstring);
- get_field(val->sam_nonce,8,asn1_decode_int32);
- get_field(val->sam_etype, 9, asn1_decode_int32);
- end_structure();
- val->magic = KV5M_SAM_CHALLENGE;
- }
- return 0;
-error_out:
- krb5_free_sam_challenge_2_body_contents(NULL, val);
- return retval;
-}
-asn1_error_code
-asn1_decode_enc_sam_key(asn1buf *buf, krb5_sam_key *val)
-{
- setup();
- val->sam_key.contents = NULL;
- { begin_structure();
- get_field(val->sam_key,0,asn1_decode_encryption_key);
- end_structure();
- val->magic = KV5M_SAM_KEY;
- }
- return 0;
-error_out:
- krb5_free_keyblock_contents(NULL, &val->sam_key);
- return retval;
-}
-
-asn1_error_code
-asn1_decode_enc_sam_response_enc(asn1buf *buf, krb5_enc_sam_response_enc *val)
-{
- setup();
- val->sam_sad.data = NULL;
- { begin_structure();
- opt_field(val->sam_nonce,0,asn1_decode_int32,0);
- opt_field(val->sam_timestamp,1,asn1_decode_kerberos_time,0);
- opt_field(val->sam_usec,2,asn1_decode_int32,0);
- opt_string(val->sam_sad,3,asn1_decode_charstring);
- end_structure();
- val->magic = KV5M_ENC_SAM_RESPONSE_ENC;
- }
- return 0;
-error_out:
- krb5_free_enc_sam_response_enc_contents(NULL, val);
- return retval;
-}
-
-asn1_error_code
-asn1_decode_enc_sam_response_enc_2(asn1buf *buf, krb5_enc_sam_response_enc_2 *val)
-{
- setup();
- val->sam_sad.data = NULL;
- { begin_structure();
- get_field(val->sam_nonce,0,asn1_decode_int32);
- opt_string(val->sam_sad,1,asn1_decode_charstring);
- end_structure();
- val->magic = KV5M_ENC_SAM_RESPONSE_ENC_2;
- }
- return 0;
-error_out:
- krb5_free_enc_sam_response_enc_2_contents(NULL, val);
- return retval;
-}
-
-#define opt_encfield(fld,tag,fn) \
- if (tagnum == tag) { \
- get_field(fld,tag,fn); } \
- else { \
- fld.magic = 0; \
- fld.enctype = 0; \
- fld.kvno = 0; \
- fld.ciphertext.data = NULL; \
- fld.ciphertext.length = 0; \
- }
-
-asn1_error_code
-asn1_decode_sam_response(asn1buf *buf, krb5_sam_response *val)
-{
- setup();
- val->sam_track_id.data = NULL;
- val->sam_enc_key.ciphertext.data = NULL;
- val->sam_enc_nonce_or_ts.ciphertext.data = NULL;
- { begin_structure();
- get_field(val->sam_type,0,asn1_decode_int32);
- get_field(val->sam_flags,1,asn1_decode_sam_flags);
- opt_string(val->sam_track_id,2,asn1_decode_charstring);
- opt_encfield(val->sam_enc_key,3,asn1_decode_encrypted_data);
- get_field(val->sam_enc_nonce_or_ts,4,asn1_decode_encrypted_data);
- opt_field(val->sam_nonce,5,asn1_decode_int32,0);
- opt_field(val->sam_patimestamp,6,asn1_decode_kerberos_time,0);
- end_structure();
- val->magic = KV5M_SAM_RESPONSE;
- }
- return 0;
-error_out:
- krb5_free_sam_response_contents(NULL, val);
- return retval;
-}
-
-asn1_error_code
-asn1_decode_sam_response_2(asn1buf *buf, krb5_sam_response_2 *val)
-{
- setup();
- val->sam_track_id.data = NULL;
- val->sam_enc_nonce_or_sad.ciphertext.data = NULL;
- { begin_structure();
- get_field(val->sam_type,0,asn1_decode_int32);
- get_field(val->sam_flags,1,asn1_decode_sam_flags);
- opt_string(val->sam_track_id,2,asn1_decode_charstring);
- get_field(val->sam_enc_nonce_or_sad,3,asn1_decode_encrypted_data);
- get_field(val->sam_nonce,4,asn1_decode_int32);
- end_structure();
- val->magic = KV5M_SAM_RESPONSE;
- }
- return 0;
-error_out:
- krb5_free_sam_response_2_contents(NULL, val);
- return retval;
-}
-
-
-asn1_error_code
-asn1_decode_predicted_sam_response(asn1buf *buf,
- krb5_predicted_sam_response *val)
-{
- setup();
- val->sam_key.contents = NULL;
- val->client = NULL;
- val->msd.data = NULL;
- { begin_structure();
- get_field(val->sam_key,0,asn1_decode_encryption_key);
- get_field(val->sam_flags,1,asn1_decode_sam_flags);
- get_field(val->stime,2,asn1_decode_kerberos_time);
- get_field(val->susec,3,asn1_decode_int32);
- alloc_principal(val->client);
- get_field(val->client,4,asn1_decode_realm);
- get_field(val->client,5,asn1_decode_principal_name);
- opt_string(val->msd,6,asn1_decode_charstring); /* should be octet */
- end_structure();
- val->magic = KV5M_PREDICTED_SAM_RESPONSE;
- }
- return 0;
-error_out:
- krb5_free_predicted_sam_response_contents(NULL, val);
- return retval;
-}
-
asn1_error_code
asn1_decode_setpw_req(asn1buf *buf, krb5_data *newpasswd,
krb5_principal *principal)
return retval;
}
-asn1_error_code
-asn1_decode_fast_armor(asn1buf *buf, krb5_fast_armor *val)
-{
- setup();
- val->armor_value.data = NULL;
- {begin_structure();
- get_field(val->armor_type, 0, asn1_decode_int32);
- get_lenfield(val->armor_value.length, val->armor_value.data,
- 1, asn1_decode_charstring);
- end_structure();
- }
- return 0;
-error_out:
- krb5_free_data_contents( NULL, &val->armor_value);
- return retval;
-}
-
-asn1_error_code
-asn1_decode_fast_armor_ptr(asn1buf *buf, krb5_fast_armor **valptr)
-{
- decode_ptr(krb5_fast_armor *, asn1_decode_fast_armor);
-}
-
-asn1_error_code
-asn1_decode_fast_finished(asn1buf *buf, krb5_fast_finished *val)
-{
- setup();
- val->client = NULL;
- val->ticket_checksum.contents = NULL;
- {begin_structure();
- get_field(val->timestamp, 0, asn1_decode_kerberos_time);
- get_field(val->usec, 1, asn1_decode_int32);
- alloc_field(val->client);
- get_field(val->client, 2, asn1_decode_realm);
- get_field(val->client, 3, asn1_decode_principal_name);
- get_field(val->ticket_checksum, 4, asn1_decode_checksum);
- end_structure();
- }
- return 0;
-error_out:
- krb5_free_principal(NULL, val->client);
- krb5_free_checksum_contents( NULL, &val->ticket_checksum);
- return retval;
-}
-asn1_error_code
-asn1_decode_fast_finished_ptr(asn1buf *buf, krb5_fast_finished **valptr)
-{
- decode_ptr( krb5_fast_finished *, asn1_decode_fast_finished);
-}
-
asn1_error_code
asn1_decode_ad_kdcissued(asn1buf *buf, krb5_ad_kdcissued *val)
{
free_external_principal_identifier);
}
-asn1_error_code
-asn1_decode_pa_pk_as_req(asn1buf *buf, krb5_pa_pk_as_req *val)
-{
- setup();
- val->signedAuthPack.data = NULL;
- val->trustedCertifiers = NULL;
- val->kdcPkId.data = NULL;
- {
- begin_structure();
- get_implicit_octet_string(val->signedAuthPack.length, val->signedAuthPack.data, 0);
- opt_field(val->trustedCertifiers, 1, asn1_decode_sequence_of_external_principal_identifier, NULL);
- opt_implicit_octet_string(val->kdcPkId.length, val->kdcPkId.data, 2);
- end_structure();
- }
- return 0;
-error_out:
- free(val->signedAuthPack.data);
- free(val->trustedCertifiers);
- free(val->kdcPkId.data);
- val->signedAuthPack.data = NULL;
- val->trustedCertifiers = NULL;
- val->kdcPkId.data = NULL;
- return retval;
-}
-
#if 0 /* XXX This needs to be tested!!! XXX */
asn1_error_code
asn1_decode_trusted_ca(asn1buf *buf, krb5_trusted_ca *val)
val->choice = choice_trusted_cas_UNKNOWN;
return retval;
}
-#endif
+#endif /* if 0 */
asn1_error_code
asn1_decode_trusted_ca_ptr(asn1buf *buf, krb5_trusted_ca **valptr)
free_trusted_ca);
}
-asn1_error_code
-asn1_decode_pa_pk_as_req_draft9(asn1buf *buf, krb5_pa_pk_as_req_draft9 *val)
-{
- int i;
- setup();
- val->signedAuthPack.data = NULL;
- val->kdcCert.data = NULL;
- val->encryptionCert.data = NULL;
- val->trustedCertifiers = NULL;
- { begin_structure();
- get_implicit_octet_string(val->signedAuthPack.length, val->signedAuthPack.data, 0);
- opt_field(val->trustedCertifiers, 1, asn1_decode_sequence_of_trusted_ca, NULL);
- opt_lenfield(val->kdcCert.length, val->kdcCert.data, 2, asn1_decode_octetstring);
- opt_lenfield(val->encryptionCert.length, val->encryptionCert.data, 2, asn1_decode_octetstring);
- end_structure();
- }
- return 0;
-error_out:
- free(val->signedAuthPack.data);
- free(val->kdcCert.data);
- free(val->encryptionCert.data);
- if (val->trustedCertifiers) {
- for (i = 0; val->trustedCertifiers[i]; i++)
- free_trusted_ca(NULL, val->trustedCertifiers[i]);
- free(val->trustedCertifiers);
- }
- val->signedAuthPack.data = NULL;
- val->kdcCert.data = NULL;
- val->encryptionCert.data = NULL;
- val->trustedCertifiers = NULL;
- return retval;
-}
-
asn1_error_code
asn1_decode_dh_rep_info(asn1buf *buf, krb5_dh_rep_info *val)
{
return retval;
}
-asn1_error_code
-asn1_decode_auth_pack(asn1buf *buf, krb5_auth_pack *val)
-{
- int i;
- setup();
- val->clientPublicValue = NULL;
- val->pkAuthenticator.paChecksum.contents = NULL;
- val->supportedCMSTypes = NULL;
- val->clientDHNonce.data = NULL;
- { begin_structure();
- get_field(val->pkAuthenticator, 0, asn1_decode_pk_authenticator);
- if (tagnum == 1) {
- alloc_field(val->clientPublicValue);
- val->clientPublicValue->algorithm.algorithm.data = NULL;
- val->clientPublicValue->algorithm.parameters.data = NULL;
- val->clientPublicValue->subjectPublicKey.data = NULL;
- }
- /* can't call opt_field because it does decoder(&subbuf, &(val)); */
- if (asn1buf_remains(&subbuf, seqindef)) {
- if ((asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED)
- && (tagnum || taglen || asn1class != UNIVERSAL))
- clean_return(ASN1_BAD_ID);
- if (tagnum == 1) {
- retval = asn1_decode_subject_pk_info(&subbuf,
- val->clientPublicValue);
- if (retval) clean_return(retval);
- if (!taglen && indef) { get_eoc(); }
- next_tag();
- } else val->clientPublicValue = NULL;
- }
- /* can't call opt_field because it does decoder(&subbuf, &(val)); */
- if (asn1buf_remains(&subbuf, seqindef)) {
- if (tagnum == 2) {
- retval = asn1_decode_sequence_of_algorithm_identifier(&subbuf, &val->supportedCMSTypes);
- if (retval) clean_return(retval);
- if (!taglen && indef) { get_eoc(); }
- next_tag();
- } else val->supportedCMSTypes = NULL;
- }
- opt_lenfield(val->clientDHNonce.length, val->clientDHNonce.data, 3, asn1_decode_octetstring);
- end_structure();
- }
- return 0;
-error_out:
- if (val->clientPublicValue) {
- free(val->clientPublicValue->algorithm.algorithm.data);
- free(val->clientPublicValue->algorithm.parameters.data);
- free(val->clientPublicValue->subjectPublicKey.data);
- free(val->clientPublicValue);
- }
- free(val->pkAuthenticator.paChecksum.contents);
- if (val->supportedCMSTypes) {
- for (i = 0; val->supportedCMSTypes[i]; i++)
- free_algorithm_identifier(NULL, val->supportedCMSTypes[i]);
- free(val->supportedCMSTypes);
- }
- free(val->clientDHNonce.data);
- val->clientPublicValue = NULL;
- val->pkAuthenticator.paChecksum.contents = NULL;
- val->supportedCMSTypes = NULL;
- val->clientDHNonce.data = NULL;
- return retval;
-}
-
-asn1_error_code
-asn1_decode_auth_pack_draft9(asn1buf *buf, krb5_auth_pack_draft9 *val)
-{
- setup();
- val->pkAuthenticator.kdcName = NULL;
- val->clientPublicValue = NULL;
- { begin_structure();
- get_field(val->pkAuthenticator, 0, asn1_decode_pk_authenticator_draft9);
- if (tagnum == 1) {
- alloc_field(val->clientPublicValue);
- val->clientPublicValue->algorithm.algorithm.data = NULL;
- val->clientPublicValue->algorithm.parameters.data = NULL;
- val->clientPublicValue->subjectPublicKey.data = NULL;
- /* can't call opt_field because it does decoder(&subbuf, &(val)); */
- if (asn1buf_remains(&subbuf, seqindef)) {
- if ((asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED)
- && (tagnum || taglen || asn1class != UNIVERSAL))
- clean_return(ASN1_BAD_ID);
- if (tagnum == 1) {
- retval = asn1_decode_subject_pk_info(&subbuf,
- val->clientPublicValue);
- if (retval) clean_return(retval);
- if (!taglen && indef) { get_eoc(); }
- next_tag();
- } else val->clientPublicValue = NULL;
- }
- }
- end_structure();
- }
- return 0;
-error_out:
- free(val->pkAuthenticator.kdcName);
- if (val->clientPublicValue) {
- free(val->clientPublicValue->algorithm.algorithm.data);
- free(val->clientPublicValue->algorithm.parameters.data);
- free(val->clientPublicValue->subjectPublicKey.data);
- free(val->clientPublicValue);
- }
- val->pkAuthenticator.kdcName = NULL;
- val->clientPublicValue = NULL;
- return retval;
-}
-
asn1_error_code
asn1_decode_pa_pk_as_rep(asn1buf *buf, krb5_pa_pk_as_rep *val)
{
--- /dev/null
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * src/lib/krb5/asn.1/asn1_k_decode_fast.c
+ *
+ * Copyright 1994, 2007, 2008, 2010 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "asn1_k_decode_macros.h"
+
+asn1_error_code
+asn1_decode_fast_armor(asn1buf *buf, krb5_fast_armor *val)
+{
+ setup();
+ val->armor_value.data = NULL;
+ {begin_structure();
+ get_field(val->armor_type, 0, asn1_decode_int32);
+ get_lenfield(val->armor_value.length, val->armor_value.data,
+ 1, asn1_decode_charstring);
+ end_structure();
+ }
+ return 0;
+error_out:
+ krb5_free_data_contents( NULL, &val->armor_value);
+ return retval;
+}
+
+asn1_error_code
+asn1_decode_fast_armor_ptr(asn1buf *buf, krb5_fast_armor **valptr)
+{
+ decode_ptr(krb5_fast_armor *, asn1_decode_fast_armor);
+}
+
+asn1_error_code
+asn1_decode_fast_finished(asn1buf *buf, krb5_fast_finished *val)
+{
+ setup();
+ val->client = NULL;
+ val->ticket_checksum.contents = NULL;
+ {begin_structure();
+ get_field(val->timestamp, 0, asn1_decode_kerberos_time);
+ get_field(val->usec, 1, asn1_decode_int32);
+ alloc_field(val->client);
+ get_field(val->client, 2, asn1_decode_realm);
+ get_field(val->client, 3, asn1_decode_principal_name);
+ get_field(val->ticket_checksum, 4, asn1_decode_checksum);
+ end_structure();
+ }
+ return 0;
+error_out:
+ krb5_free_principal(NULL, val->client);
+ krb5_free_checksum_contents( NULL, &val->ticket_checksum);
+ return retval;
+}
+
+asn1_error_code
+asn1_decode_fast_finished_ptr(asn1buf *buf, krb5_fast_finished **valptr)
+{
+ decode_ptr( krb5_fast_finished *, asn1_decode_fast_finished);
+}
+
--- /dev/null
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * src/lib/krb5/asn.1/asn1_k_decode_kdc.c
+ *
+ * Copyright 1994, 2007, 2008, 2010 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "asn1_k_decode_macros.h"
+
+asn1_error_code
+asn1_decode_kdc_req(asn1buf *buf, krb5_kdc_req *val)
+{
+ setup();
+ val->padata = NULL;
+ { begin_structure();
+ { krb5_kvno kvno;
+ get_field(kvno,1,asn1_decode_kvno);
+ if (kvno != KVNO) clean_return(KRB5KDC_ERR_BAD_PVNO); }
+ get_field(val->msg_type,2,asn1_decode_msgtype);
+ opt_field(val->padata,3,asn1_decode_sequence_of_pa_data,NULL);
+ get_field(*val,4,asn1_decode_kdc_req_body);
+ end_structure();
+ val->magic = KV5M_KDC_REQ;
+ }
+ return 0;
+error_out:
+ krb5_free_pa_data(NULL, val->padata);
+ val->padata = NULL;
+ return retval;
+}
+
+asn1_error_code
+asn1_decode_kdc_req_body(asn1buf *buf, krb5_kdc_req *val)
+{
+ setup();
+ val->client = NULL;
+ val->server = NULL;
+ val->ktype = NULL;
+ val->addresses = NULL;
+ val->authorization_data.ciphertext.data = NULL;
+ val->unenc_authdata = NULL;
+ val->second_ticket = NULL;
+ {
+ krb5_principal psave;
+ begin_structure();
+ get_field(val->kdc_options,0,asn1_decode_kdc_options);
+ if (tagnum == 1) { alloc_principal(val->client); }
+ opt_field(val->client,1,asn1_decode_principal_name,NULL);
+ alloc_principal(val->server);
+ get_field(val->server,2,asn1_decode_realm);
+ if (val->client != NULL) {
+ retval = asn1_krb5_realm_copy(val->client,val->server);
+ if (retval) clean_return(retval); }
+
+ /* If opt_field server is missing, memory reference to server is
+ * lost and results in memory leak
+ */
+ psave = val->server;
+ opt_field(val->server,3,asn1_decode_principal_name,NULL);
+ if (val->server == NULL) {
+ if (psave->realm.data) {
+ free(psave->realm.data);
+ psave->realm.data = NULL;
+ psave->realm.length=0;
+ }
+ free(psave);
+ }
+ opt_field(val->from,4,asn1_decode_kerberos_time,0);
+ get_field(val->till,5,asn1_decode_kerberos_time);
+ opt_field(val->rtime,6,asn1_decode_kerberos_time,0);
+ get_field(val->nonce,7,asn1_decode_int32);
+ get_lenfield(val->nktypes,val->ktype,8,asn1_decode_sequence_of_enctype);
+ opt_field(val->addresses,9,asn1_decode_host_addresses,0);
+ if (tagnum == 10) {
+ get_field(val->authorization_data,10,asn1_decode_encrypted_data); }
+ else {
+ val->authorization_data.magic = KV5M_ENC_DATA;
+ val->authorization_data.enctype = 0;
+ val->authorization_data.kvno = 0;
+ val->authorization_data.ciphertext.data = NULL;
+ val->authorization_data.ciphertext.length = 0;
+ }
+ opt_field(val->second_ticket,11,asn1_decode_sequence_of_ticket,NULL);
+ end_structure();
+ val->magic = KV5M_KDC_REQ;
+ }
+ return 0;
+error_out:
+ krb5_free_principal(NULL, val->client);
+ krb5_free_principal(NULL, val->server);
+ free(val->ktype);
+ krb5_free_addresses(NULL, val->addresses);
+ krb5_free_data_contents(NULL, &val->authorization_data.ciphertext);
+ krb5_free_tickets(NULL, val->second_ticket);
+ val->client = NULL;
+ val->server = NULL;
+ val->ktype = NULL;
+ val->addresses = NULL;
+ val->unenc_authdata = NULL;
+ val->second_ticket = NULL;
+ return retval;
+}
+
+#ifndef DISABLE_PKINIT
+/* PKINIT */
+asn1_error_code
+asn1_decode_pa_pk_as_req(asn1buf *buf, krb5_pa_pk_as_req *val)
+{
+ setup();
+ val->signedAuthPack.data = NULL;
+ val->trustedCertifiers = NULL;
+ val->kdcPkId.data = NULL;
+ {
+ begin_structure();
+ get_implicit_octet_string(val->signedAuthPack.length, val->signedAuthPack.data, 0);
+ opt_field(val->trustedCertifiers, 1, asn1_decode_sequence_of_external_principal_identifier, NULL);
+ opt_implicit_octet_string(val->kdcPkId.length, val->kdcPkId.data, 2);
+ end_structure();
+ }
+ return 0;
+error_out:
+ free(val->signedAuthPack.data);
+ free(val->trustedCertifiers);
+ free(val->kdcPkId.data);
+ val->signedAuthPack.data = NULL;
+ val->trustedCertifiers = NULL;
+ val->kdcPkId.data = NULL;
+ return retval;
+}
+
+static void
+free_trusted_ca(void *dummy, krb5_trusted_ca *val)
+{
+ if (val->choice == choice_trusted_cas_caName)
+ free(val->u.caName.data);
+ else if (val->choice == choice_trusted_cas_issuerAndSerial)
+ free(val->u.issuerAndSerial.data);
+ free(val);
+}
+
+asn1_error_code
+asn1_decode_pa_pk_as_req_draft9(asn1buf *buf, krb5_pa_pk_as_req_draft9 *val)
+{
+ int i;
+ setup();
+ val->signedAuthPack.data = NULL;
+ val->kdcCert.data = NULL;
+ val->encryptionCert.data = NULL;
+ val->trustedCertifiers = NULL;
+ { begin_structure();
+ get_implicit_octet_string(val->signedAuthPack.length, val->signedAuthPack.data, 0);
+ opt_field(val->trustedCertifiers, 1, asn1_decode_sequence_of_trusted_ca, NULL);
+ opt_lenfield(val->kdcCert.length, val->kdcCert.data, 2, asn1_decode_octetstring);
+ opt_lenfield(val->encryptionCert.length, val->encryptionCert.data, 2, asn1_decode_octetstring);
+ end_structure();
+ }
+ return 0;
+error_out:
+ free(val->signedAuthPack.data);
+ free(val->kdcCert.data);
+ free(val->encryptionCert.data);
+ if (val->trustedCertifiers) {
+ for (i = 0; val->trustedCertifiers[i]; i++)
+ free_trusted_ca(NULL, val->trustedCertifiers[i]);
+ free(val->trustedCertifiers);
+ }
+ val->signedAuthPack.data = NULL;
+ val->kdcCert.data = NULL;
+ val->encryptionCert.data = NULL;
+ val->trustedCertifiers = NULL;
+ return retval;
+}
+
+static void
+free_algorithm_identifier(krb5_algorithm_identifier *val)
+{
+ free(val->algorithm.data);
+ free(val->parameters.data);
+ free(val);
+}
+
+asn1_error_code
+asn1_decode_auth_pack(asn1buf *buf, krb5_auth_pack *val)
+{
+ int i;
+ setup();
+ val->clientPublicValue = NULL;
+ val->pkAuthenticator.paChecksum.contents = NULL;
+ val->supportedCMSTypes = NULL;
+ val->clientDHNonce.data = NULL;
+ { begin_structure();
+ get_field(val->pkAuthenticator, 0, asn1_decode_pk_authenticator);
+ if (tagnum == 1) {
+ alloc_field(val->clientPublicValue);
+ val->clientPublicValue->algorithm.algorithm.data = NULL;
+ val->clientPublicValue->algorithm.parameters.data = NULL;
+ val->clientPublicValue->subjectPublicKey.data = NULL;
+ }
+ /* can't call opt_field because it does decoder(&subbuf, &(val)); */
+ if (asn1buf_remains(&subbuf, seqindef)) {
+ if ((asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED)
+ && (tagnum || taglen || asn1class != UNIVERSAL))
+ clean_return(ASN1_BAD_ID);
+ if (tagnum == 1) {
+ retval = asn1_decode_subject_pk_info(&subbuf,
+ val->clientPublicValue);
+ if (retval) clean_return(retval);
+ if (!taglen && indef) { get_eoc(); }
+ next_tag();
+ } else val->clientPublicValue = NULL;
+ }
+ /* can't call opt_field because it does decoder(&subbuf, &(val)); */
+ if (asn1buf_remains(&subbuf, seqindef)) {
+ if (tagnum == 2) {
+ retval = asn1_decode_sequence_of_algorithm_identifier(&subbuf, &val->supportedCMSTypes);
+ if (retval) clean_return(retval);
+ if (!taglen && indef) { get_eoc(); }
+ next_tag();
+ } else val->supportedCMSTypes = NULL;
+ }
+ opt_lenfield(val->clientDHNonce.length, val->clientDHNonce.data, 3, asn1_decode_octetstring);
+ end_structure();
+ }
+ return 0;
+error_out:
+ if (val->clientPublicValue) {
+ free(val->clientPublicValue->algorithm.algorithm.data);
+ free(val->clientPublicValue->algorithm.parameters.data);
+ free(val->clientPublicValue->subjectPublicKey.data);
+ free(val->clientPublicValue);
+ }
+ free(val->pkAuthenticator.paChecksum.contents);
+ if (val->supportedCMSTypes) {
+ for (i = 0; val->supportedCMSTypes[i]; i++)
+ free_algorithm_identifier(val->supportedCMSTypes[i]);
+ free(val->supportedCMSTypes);
+ }
+ free(val->clientDHNonce.data);
+ val->clientPublicValue = NULL;
+ val->pkAuthenticator.paChecksum.contents = NULL;
+ val->supportedCMSTypes = NULL;
+ val->clientDHNonce.data = NULL;
+ return retval;
+}
+
+asn1_error_code
+asn1_decode_auth_pack_draft9(asn1buf *buf, krb5_auth_pack_draft9 *val)
+{
+ setup();
+ val->pkAuthenticator.kdcName = NULL;
+ val->clientPublicValue = NULL;
+ { begin_structure();
+ get_field(val->pkAuthenticator, 0, asn1_decode_pk_authenticator_draft9);
+ if (tagnum == 1) {
+ alloc_field(val->clientPublicValue);
+ val->clientPublicValue->algorithm.algorithm.data = NULL;
+ val->clientPublicValue->algorithm.parameters.data = NULL;
+ val->clientPublicValue->subjectPublicKey.data = NULL;
+ /* can't call opt_field because it does decoder(&subbuf, &(val)); */
+ if (asn1buf_remains(&subbuf, seqindef)) {
+ if ((asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED)
+ && (tagnum || taglen || asn1class != UNIVERSAL))
+ clean_return(ASN1_BAD_ID);
+ if (tagnum == 1) {
+ retval = asn1_decode_subject_pk_info(&subbuf,
+ val->clientPublicValue);
+ if (retval) clean_return(retval);
+ if (!taglen && indef) { get_eoc(); }
+ next_tag();
+ } else val->clientPublicValue = NULL;
+ }
+ }
+ end_structure();
+ }
+ return 0;
+error_out:
+ free(val->pkAuthenticator.kdcName);
+ if (val->clientPublicValue) {
+ free(val->clientPublicValue->algorithm.algorithm.data);
+ free(val->clientPublicValue->algorithm.parameters.data);
+ free(val->clientPublicValue->subjectPublicKey.data);
+ free(val->clientPublicValue);
+ }
+ val->pkAuthenticator.kdcName = NULL;
+ val->clientPublicValue = NULL;
+ return retval;
+}
+
+#endif /* DISABLE_PKINIT */
--- /dev/null
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * src/lib/krb5/asn.1/asn1_k_decode_macros.h
+ *
+ * Copyright 1994, 2007, 2008, 2010 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifndef ASN1_DECODE_KRB5_MACROS_H
+#define ASN1_DECODE_KRB5_MACROS_H
+
+#include "asn1_k_decode.h"
+#include "asn1_decode.h"
+#include "asn1_get.h"
+#include "asn1_misc.h"
+
+#define clean_return(val) { retval = val; goto error_out; }
+
+/* Declare useful decoder variables. */
+#define setup() \
+ asn1_error_code retval; \
+ asn1_class asn1class; \
+ asn1_construction construction; \
+ asn1_tagnum tagnum; \
+ unsigned int length, taglen
+
+#define unused_var(x) if (0) { x = 0; x = x - x; }
+
+/* This is used for prefetch of next tag in sequence. */
+#define next_tag() \
+ { taginfo t2; \
+ retval = asn1_get_tag_2(&subbuf, &t2); \
+ if (retval) clean_return(retval); \
+ /* Copy out to match previous functionality, until better integrated. */ \
+ asn1class = t2.asn1class; \
+ construction = t2.construction; \
+ tagnum = t2.tagnum; \
+ taglen = t2.length; \
+ indef = t2.indef; \
+ }
+
+static asn1_error_code
+asn1_get_eoc_tag (asn1buf *buf)
+{
+ asn1_error_code retval;
+ taginfo t;
+
+ retval = asn1_get_tag_2(buf, &t);
+ if (retval)
+ return retval;
+ if (t.asn1class != UNIVERSAL || t.tagnum || t.indef)
+ return ASN1_MISSING_EOC;
+ return 0;
+}
+
+/* Force check for EOC tag. */
+#define get_eoc() \
+ { \
+ retval = asn1_get_eoc_tag(&subbuf); \
+ if (retval) clean_return(retval); \
+ }
+
+#define alloc_field(var) \
+ var = calloc(1, sizeof(*var)); \
+ if ((var) == NULL) clean_return(ENOMEM)
+
+/*
+ * Allocate a principal and initialize enough fields for
+ * krb5_free_principal to have defined behavior.
+ */
+#define alloc_principal(var) \
+ alloc_field(var); \
+ var->realm.data = NULL; \
+ var->data = NULL
+
+/*
+ * Allocate a data structure and initialize enough fields for
+ * krb5_free_data to have defined behavior.
+ */
+#define alloc_data(var) \
+ alloc_field(var); \
+ var->data = NULL
+
+/* Fetch an expected APPLICATION class tag and verify. */
+#define apptag(tagexpect) \
+ { \
+ taginfo t1; \
+ retval = asn1_get_tag_2(buf, &t1); \
+ if (retval) clean_return(retval); \
+ if (t1.asn1class != APPLICATION || t1.construction != CONSTRUCTED || \
+ t1.tagnum != (tagexpect)) clean_return(ASN1_BAD_ID); \
+ /* Copy out to match previous functionality, until better integrated. */ \
+ asn1class = t1.asn1class; \
+ construction = t1.construction; \
+ tagnum = t1.tagnum; \
+ applen = t1.length; \
+ }
+
+/**** normal fields ****/
+
+/*
+ * get_field_body
+ *
+ * Get bare field. This also prefetches the next tag. The call to
+ * get_eoc() assumes that any values fetched by this macro are
+ * enclosed in a context-specific tag.
+ */
+#define get_field_body(var, decoder) \
+ retval = decoder(&subbuf, &(var)); \
+ if (retval) clean_return(retval); \
+ if (!taglen && indef) { get_eoc(); } \
+ next_tag()
+
+/*
+ * error_if_bad_tag
+ *
+ * Checks that the next tag is the expected one; returns with an error
+ * if not.
+ */
+#define error_if_bad_tag(tagexpect) \
+ if (tagnum != (tagexpect)) { clean_return((tagnum < (tagexpect)) ? ASN1_MISPLACED_FIELD : ASN1_MISSING_FIELD); }
+
+/*
+ * get_field
+ *
+ * Get field having an expected context specific tag. This assumes
+ * that context-specific tags are monotonically increasing in its
+ * verification of tag numbers.
+ */
+#define get_field(var, tagexpect, decoder) \
+ error_if_bad_tag(tagexpect); \
+ if ((asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED) \
+ && (tagnum || taglen || asn1class != UNIVERSAL)) \
+ clean_return(ASN1_BAD_ID); \
+ get_field_body(var,decoder)
+
+/*
+ * opt_field
+ *
+ * Get an optional field with an expected context specific tag.
+ * Assumes that OPTVAL will have the default value, thus failing to
+ * distinguish between absent optional values and present optional
+ * values that happen to have the value of OPTVAL.
+ */
+#define opt_field(var, tagexpect, decoder, optvalue) \
+ if (asn1buf_remains(&subbuf, seqindef)) { \
+ if ((asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED) \
+ && (tagnum || taglen || asn1class != UNIVERSAL)) \
+ clean_return(ASN1_BAD_ID); \
+ if (tagnum == (tagexpect)) { \
+ get_field_body(var, decoder); \
+ } else var = optvalue; \
+ }
+
+/**** fields w/ length ****/
+
+/* similar to get_field_body */
+#define get_lenfield_body(len, var, decoder) \
+ retval = decoder(&subbuf, &(len), &(var)); \
+ if (retval) clean_return(retval); \
+ if (!taglen && indef) { get_eoc(); } \
+ next_tag()
+
+/* similar to get_field_body */
+#define get_lenfield(len, var, tagexpect, decoder) \
+ error_if_bad_tag(tagexpect); \
+ if ((asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED) \
+ && (tagnum || taglen || asn1class != UNIVERSAL)) \
+ clean_return(ASN1_BAD_ID); \
+ get_lenfield_body(len, var, decoder)
+
+/* similar to opt_field */
+#define opt_lenfield(len, var, tagexpect, decoder) \
+ if (tagnum == (tagexpect)) { \
+ get_lenfield_body(len, var, decoder); \
+ } else { len = 0; var = 0; }
+
+/*
+ * Deal with implicitly tagged fields
+ */
+#define get_implicit_octet_string(len, var, tagexpect) \
+ if (tagnum != (tagexpect)) clean_return(ASN1_MISSING_FIELD); \
+ if (asn1class != CONTEXT_SPECIFIC || construction != PRIMITIVE) \
+ clean_return(ASN1_BAD_ID); \
+ retval = asn1buf_remove_octetstring(&subbuf, taglen, &(var)); \
+ if (retval) clean_return(retval); \
+ (len) = taglen; \
+ next_tag()
+
+#define opt_implicit_octet_string(len, var, tagexpect) \
+ if (tagnum == (tagexpect)) { \
+ if (asn1class != CONTEXT_SPECIFIC || construction != PRIMITIVE) \
+ clean_return(ASN1_BAD_ID); \
+ retval = asn1buf_remove_octetstring(&subbuf, taglen, &(var)); \
+ if (retval) clean_return(retval); \
+ (len) = taglen; \
+ next_tag(); \
+ } else { (len) = 0; (var) = NULL; }
+
+/*
+ * begin_structure
+ *
+ * Declares some variables for decoding SEQUENCE types. This is meant
+ * to be called in an inner block that ends with a call to
+ * end_structure().
+ */
+#define begin_structure() \
+ asn1buf subbuf; \
+ int seqindef; \
+ int indef; \
+ retval = asn1_get_sequence(buf, &length, &seqindef); \
+ if (retval) clean_return(retval); \
+ retval = asn1buf_imbed(&subbuf, buf, length, seqindef); \
+ if (retval) clean_return(retval); \
+ next_tag()
+
+/*
+ * This is used for structures which have no tagging.
+ * It is the same as begin_structure() except next_tag()
+ * is not called.
+ */
+#define begin_structure_no_tag() \
+ asn1buf subbuf; \
+ int seqindef; \
+ int indef; \
+ retval = asn1_get_sequence(buf, &length, &seqindef); \
+ if (retval) clean_return(retval); \
+ retval = asn1buf_imbed(&subbuf, buf, length, seqindef); \
+ if (retval) clean_return(retval)
+
+/* skip trailing garbage */
+#define end_structure() \
+ retval = asn1buf_sync(buf, &subbuf, asn1class, tagnum, \
+ length, indef, seqindef); \
+ if (retval) clean_return(retval)
+
+/*
+ * begin_choice
+ *
+ * Declares some variables for decoding CHOICE types. This is meant
+ * to be called in an inner block that ends with a call to
+ * end_choice().
+ */
+#define begin_choice() \
+ asn1buf subbuf; \
+ int seqindef; \
+ int indef; \
+ taginfo t; \
+ retval = asn1_get_tag_2(buf, &t); \
+ if (retval) clean_return(retval); \
+ tagnum = t.tagnum; \
+ taglen = t.length; \
+ indef = t.indef; \
+ length = t.length; \
+ seqindef = t.indef; \
+ asn1class = t.asn1class; \
+ construction = t.construction; \
+ retval = asn1buf_imbed(&subbuf, buf, length, seqindef); \
+ if (retval) clean_return(retval)
+
+/* skip trailing garbage */
+#define end_choice() \
+ length -= t.length; \
+ retval = asn1buf_sync(buf, &subbuf, t.asn1class, t.tagnum, \
+ length, t.indef, seqindef); \
+ if (retval) clean_return(retval)
+
+/*
+ * sequence_of
+ *
+ * Declares some variables for decoding SEQUENCE OF types. This is
+ * meant to be called in an inner block that ends with a call to
+ * end_sequence_of().
+ */
+#define sequence_of(buf) \
+ unsigned int length, taglen; \
+ asn1_class asn1class; \
+ asn1_construction construction; \
+ asn1_tagnum tagnum; \
+ int indef; \
+ sequence_of_common(buf)
+
+/*
+ * sequence_of_no_tagvars
+ *
+ * This is meant for use inside decoder functions that have an outer
+ * sequence structure and thus declares variables of different names
+ * than does sequence_of() to avoid shadowing.
+ */
+#define sequence_of_no_tagvars(buf) \
+ sequence_of_common(buf)
+
+/*
+ * sequence_of_common
+ *
+ * Fetches the outer SEQUENCE OF length info into {length,seqofindef}
+ * and imbeds an inner buffer seqbuf. Unlike begin_structure(), it
+ * does not prefetch the next tag.
+ */
+#define sequence_of_common(buf) \
+ asn1buf seqbuf; \
+ int seqofindef; \
+ retval = asn1_get_sequence(buf, &length, &seqofindef); \
+ if (retval) clean_return(retval); \
+ retval = asn1buf_imbed(&seqbuf, buf, length, seqofindef); \
+ if (retval) clean_return(retval)
+
+/*
+ * end_sequence_of
+ *
+ * Attempts to fetch an EOC tag, if any, and to sync over trailing
+ * garbage, if any.
+ */
+#define end_sequence_of(buf) \
+ { \
+ taginfo t4; \
+ retval = asn1_get_tag_2(&seqbuf, &t4); \
+ if (retval) clean_return(retval); \
+ /* Copy out to match previous functionality, until better integrated. */ \
+ asn1class = t4.asn1class; \
+ construction = t4.construction; \
+ tagnum = t4.tagnum; \
+ taglen = t4.length; \
+ indef = t4.indef; \
+ } \
+ retval = asn1buf_sync(buf, &seqbuf, asn1class, tagnum, \
+ length, indef, seqofindef); \
+ if (retval) clean_return(retval);
+
+/*
+ * end_sequence_of_no_tagvars
+ *
+ * Like end_sequence_of(), but uses the different (non-shadowing)
+ * variable names.
+ */
+static asn1_error_code
+end_sequence_of_no_tagvars_helper(asn1buf *buf, asn1buf *seqbufp,
+ int seqofindef)
+{
+ taginfo t;
+ asn1_error_code retval;
+
+ retval = asn1_get_tag_2(seqbufp, &t);
+ if (retval)
+ return retval;
+ retval = asn1buf_sync(buf, seqbufp, t.asn1class, t.tagnum,
+ t.length, t.indef, seqofindef);
+ return retval;
+}
+#define end_sequence_of_no_tagvars(buf) \
+ retval = end_sequence_of_no_tagvars_helper(buf, &seqbuf, seqofindef); \
+ if (retval) clean_return(retval)
+
+/*
+ * Function body for a pointer decoder, which allocates a pointer
+ * field and invokes a structure decoder to fill it in. Pointer
+ * decoders always fill in their output parameters with NULL (on
+ * error) or a valid constructed structure, making cleanup easier on
+ * callers.
+ */
+#define decode_ptr(type, structure_decoder) \
+ type val; \
+ asn1_error_code retval; \
+ \
+ *valptr = NULL; \
+ val = calloc(1, sizeof(*val)); \
+ if (!val) \
+ return ENOMEM; \
+ retval = structure_decoder(buf, val); \
+ if (retval) { \
+ free(val); \
+ return retval; \
+ } \
+ *valptr = val; \
+ return 0;
+#define integer_convert(fname,ktype) \
+ asn1_error_code fname(asn1buf * buf, ktype * val) \
+ { \
+ asn1_error_code retval; \
+ long n; \
+ retval = asn1_decode_integer(buf,&n); \
+ if (retval) return retval; \
+ *val = (ktype)n; \
+ return 0; \
+ }
+#define unsigned_integer_convert(fname,ktype) \
+ asn1_error_code fname(asn1buf * buf, ktype * val) \
+ { \
+ asn1_error_code retval; \
+ unsigned long n; \
+ retval = asn1_decode_unsigned_integer(buf,&n); \
+ if (retval) return retval; \
+ *val = (ktype)n; \
+ return 0; \
+ }
+#endif
--- /dev/null
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * src/lib/krb5/asn.1/asn1_k_decode_sam.c
+ *
+ * Copyright 1994, 2007, 2008, 2010 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "asn1_k_decode_macros.h"
+
+asn1_error_code
+asn1_decode_sam_flags(asn1buf *buf, krb5_flags *val)
+{
+ return asn1_decode_krb5_flags(buf,val);
+}
+
+#define opt_string(val,n,fn) opt_lenfield((val).length,(val).data,n,fn)
+#define opt_cksum(var,tagexpect,decoder) \
+ if (tagnum == (tagexpect)) { \
+ get_field_body(var,decoder); } \
+ else var.length = 0
+
+asn1_error_code
+asn1_decode_sam_challenge(asn1buf *buf, krb5_sam_challenge *val)
+{
+ setup();
+ val->sam_type_name.data = NULL;
+ val->sam_track_id.data = NULL;
+ val->sam_challenge_label.data = NULL;
+ val->sam_response_prompt.data = NULL;
+ val->sam_pk_for_sad.data = NULL;
+ val->sam_cksum.contents = NULL;
+ { begin_structure();
+ get_field(val->sam_type,0,asn1_decode_int32);
+ get_field(val->sam_flags,1,asn1_decode_sam_flags);
+ opt_string(val->sam_type_name,2,asn1_decode_charstring);
+ opt_string(val->sam_track_id,3,asn1_decode_charstring);
+ opt_string(val->sam_challenge_label,4,asn1_decode_charstring);
+ opt_string(val->sam_challenge,5,asn1_decode_charstring);
+ opt_string(val->sam_response_prompt,6,asn1_decode_charstring);
+ opt_string(val->sam_pk_for_sad,7,asn1_decode_charstring);
+ opt_field(val->sam_nonce,8,asn1_decode_int32,0);
+ opt_cksum(val->sam_cksum,9,asn1_decode_checksum);
+ end_structure();
+ val->magic = KV5M_SAM_CHALLENGE;
+ }
+ return 0;
+error_out:
+ krb5_free_sam_challenge_contents(NULL, val);
+ return retval;
+}
+
+asn1_error_code
+asn1_decode_sam_challenge_2(asn1buf *buf, krb5_sam_challenge_2 *val)
+{
+ krb5_checksum **cksump;
+ setup();
+ val->sam_challenge_2_body.data = NULL;
+ val->sam_cksum = NULL;
+ { char *save, *end;
+ size_t alloclen;
+ begin_structure();
+ if (tagnum != 0) clean_return(ASN1_MISSING_FIELD);
+ if (asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED)
+ clean_return(ASN1_BAD_ID);
+ save = subbuf.next;
+ { sequence_of_no_tagvars(&subbuf);
+ end_sequence_of_no_tagvars(&subbuf);
+ }
+ end = subbuf.next;
+ alloclen = end - save;
+ val->sam_challenge_2_body.data = malloc(alloclen);
+ if (!val->sam_challenge_2_body.data)
+ clean_return(ENOMEM);
+ val->sam_challenge_2_body.length = alloclen;
+ memcpy(val->sam_challenge_2_body.data, save, alloclen);
+ next_tag();
+ get_field(val->sam_cksum, 1, asn1_decode_sequence_of_checksum);
+ end_structure();
+ }
+ return 0;
+error_out:
+ krb5_free_data_contents(NULL, &val->sam_challenge_2_body);
+ if (val->sam_cksum) {
+ for (cksump = val->sam_cksum; *cksump; cksump++)
+ krb5_free_checksum(NULL, *cksump);
+ free(val->sam_cksum);
+ val->sam_cksum = NULL;
+ }
+ return retval;
+}
+
+asn1_error_code
+asn1_decode_sam_challenge_2_body(asn1buf *buf, krb5_sam_challenge_2_body *val)
+{
+ setup();
+ val->sam_type_name.data = NULL;
+ val->sam_track_id.data = NULL;
+ val->sam_challenge_label.data = NULL;
+ val->sam_challenge.data = NULL;
+ val->sam_response_prompt.data = NULL;
+ val->sam_pk_for_sad.data = NULL;
+ { begin_structure();
+ get_field(val->sam_type,0,asn1_decode_int32);
+ get_field(val->sam_flags,1,asn1_decode_sam_flags);
+ opt_string(val->sam_type_name,2,asn1_decode_charstring);
+ opt_string(val->sam_track_id,3,asn1_decode_charstring);
+ opt_string(val->sam_challenge_label,4,asn1_decode_charstring);
+ opt_string(val->sam_challenge,5,asn1_decode_charstring);
+ opt_string(val->sam_response_prompt,6,asn1_decode_charstring);
+ opt_string(val->sam_pk_for_sad,7,asn1_decode_charstring);
+ get_field(val->sam_nonce,8,asn1_decode_int32);
+ get_field(val->sam_etype, 9, asn1_decode_int32);
+ end_structure();
+ val->magic = KV5M_SAM_CHALLENGE;
+ }
+ return 0;
+error_out:
+ krb5_free_sam_challenge_2_body_contents(NULL, val);
+ return retval;
+}
+asn1_error_code
+asn1_decode_enc_sam_key(asn1buf *buf, krb5_sam_key *val)
+{
+ setup();
+ val->sam_key.contents = NULL;
+ { begin_structure();
+ get_field(val->sam_key,0,asn1_decode_encryption_key);
+ end_structure();
+ val->magic = KV5M_SAM_KEY;
+ }
+ return 0;
+error_out:
+ krb5_free_keyblock_contents(NULL, &val->sam_key);
+ return retval;
+}
+
+asn1_error_code
+asn1_decode_enc_sam_response_enc(asn1buf *buf, krb5_enc_sam_response_enc *val)
+{
+ setup();
+ val->sam_sad.data = NULL;
+ { begin_structure();
+ opt_field(val->sam_nonce,0,asn1_decode_int32,0);
+ opt_field(val->sam_timestamp,1,asn1_decode_kerberos_time,0);
+ opt_field(val->sam_usec,2,asn1_decode_int32,0);
+ opt_string(val->sam_sad,3,asn1_decode_charstring);
+ end_structure();
+ val->magic = KV5M_ENC_SAM_RESPONSE_ENC;
+ }
+ return 0;
+error_out:
+ krb5_free_enc_sam_response_enc_contents(NULL, val);
+ return retval;
+}
+
+asn1_error_code
+asn1_decode_enc_sam_response_enc_2(asn1buf *buf, krb5_enc_sam_response_enc_2 *val)
+{
+ setup();
+ val->sam_sad.data = NULL;
+ { begin_structure();
+ get_field(val->sam_nonce,0,asn1_decode_int32);
+ opt_string(val->sam_sad,1,asn1_decode_charstring);
+ end_structure();
+ val->magic = KV5M_ENC_SAM_RESPONSE_ENC_2;
+ }
+ return 0;
+error_out:
+ krb5_free_enc_sam_response_enc_2_contents(NULL, val);
+ return retval;
+}
+
+#define opt_encfield(fld,tag,fn) \
+ if (tagnum == tag) { \
+ get_field(fld,tag,fn); } \
+ else { \
+ fld.magic = 0; \
+ fld.enctype = 0; \
+ fld.kvno = 0; \
+ fld.ciphertext.data = NULL; \
+ fld.ciphertext.length = 0; \
+ }
+
+asn1_error_code
+asn1_decode_sam_response(asn1buf *buf, krb5_sam_response *val)
+{
+ setup();
+ val->sam_track_id.data = NULL;
+ val->sam_enc_key.ciphertext.data = NULL;
+ val->sam_enc_nonce_or_ts.ciphertext.data = NULL;
+ { begin_structure();
+ get_field(val->sam_type,0,asn1_decode_int32);
+ get_field(val->sam_flags,1,asn1_decode_sam_flags);
+ opt_string(val->sam_track_id,2,asn1_decode_charstring);
+ opt_encfield(val->sam_enc_key,3,asn1_decode_encrypted_data);
+ get_field(val->sam_enc_nonce_or_ts,4,asn1_decode_encrypted_data);
+ opt_field(val->sam_nonce,5,asn1_decode_int32,0);
+ opt_field(val->sam_patimestamp,6,asn1_decode_kerberos_time,0);
+ end_structure();
+ val->magic = KV5M_SAM_RESPONSE;
+ }
+ return 0;
+error_out:
+ krb5_free_sam_response_contents(NULL, val);
+ return retval;
+}
+
+asn1_error_code
+asn1_decode_sam_response_2(asn1buf *buf, krb5_sam_response_2 *val)
+{
+ setup();
+ val->sam_track_id.data = NULL;
+ val->sam_enc_nonce_or_sad.ciphertext.data = NULL;
+ { begin_structure();
+ get_field(val->sam_type,0,asn1_decode_int32);
+ get_field(val->sam_flags,1,asn1_decode_sam_flags);
+ opt_string(val->sam_track_id,2,asn1_decode_charstring);
+ get_field(val->sam_enc_nonce_or_sad,3,asn1_decode_encrypted_data);
+ get_field(val->sam_nonce,4,asn1_decode_int32);
+ end_structure();
+ val->magic = KV5M_SAM_RESPONSE;
+ }
+ return 0;
+error_out:
+ krb5_free_sam_response_2_contents(NULL, val);
+ return retval;
+}
+
+asn1_error_code
+asn1_decode_predicted_sam_response(asn1buf *buf,
+ krb5_predicted_sam_response *val)
+{
+ setup();
+ val->sam_key.contents = NULL;
+ val->client = NULL;
+ val->msd.data = NULL;
+ { begin_structure();
+ get_field(val->sam_key,0,asn1_decode_encryption_key);
+ get_field(val->sam_flags,1,asn1_decode_sam_flags);
+ get_field(val->stime,2,asn1_decode_kerberos_time);
+ get_field(val->susec,3,asn1_decode_int32);
+ alloc_principal(val->client);
+ get_field(val->client,4,asn1_decode_realm);
+ get_field(val->client,5,asn1_decode_principal_name);
+ opt_string(val->msd,6,asn1_decode_charstring); /* should be octet */
+ end_structure();
+ val->magic = KV5M_PREDICTED_SAM_RESPONSE;
+ }
+ return 0;
+error_out:
+ krb5_free_predicted_sam_response_contents(NULL, val);
+ return retval;
+}
+
$(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
asn1_decode.h asn1_get.h asn1_k_decode.c asn1_k_decode.h \
asn1_misc.h asn1buf.h krbasn1.h
+asn1_k_decode_fast.so asn1_k_decode_fast.po $(OUTPRE)asn1_k_decode_fast.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \
+ $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
+ $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/locate_plugin.h \
+ $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/krb5/preauth_plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ asn1_decode.h asn1_get.h asn1_k_decode_fast.c asn1_k_decode.h \
+ asn1_misc.h asn1buf.h krbasn1.h
+asn1_k_decode_kdc.so asn1_k_decode_kdc.po $(OUTPRE)asn1_k_decode_kdc.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \
+ $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
+ $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/locate_plugin.h \
+ $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/krb5/preauth_plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ asn1_decode.h asn1_get.h asn1_k_decode_kdc.c asn1_k_decode.h \
+ asn1_misc.h asn1buf.h krbasn1.h
+asn1_k_decode_sam.so asn1_k_decode_sam.po $(OUTPRE)asn1_k_decode_sam.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \
+ $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
+ $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/locate_plugin.h \
+ $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/krb5/preauth_plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ asn1_decode.h asn1_get.h asn1_k_decode_sam.c asn1_k_decode.h \
+ asn1_misc.h asn1buf.h krbasn1.h
asn1_encode.so asn1_encode.po $(OUTPRE)asn1_encode.$(OBJEXT): \
$(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \
$(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
#include "asn1_k_decode.h"
#include "asn1_decode.h"
#include "asn1_get.h"
-
-/* setup *********************************************************/
-/* set up variables */
-/*
- * the setup* macros can return, but are always used at function start
- * and thus need no malloc cleanup
- */
-#define setup_buf_only(type) \
- asn1_error_code retval; \
- asn1buf buf; \
- type rep = NULL; \
- \
- *repptr = NULL; \
- retval = asn1buf_wrap_data(&buf,code); \
- if (retval) return retval
-
-#define setup_no_tagnum(type) \
- asn1_class asn1class; \
- asn1_construction construction; \
- setup_buf_only(type)
-
-#define setup_no_length(type) \
- asn1_tagnum tagnum; \
- setup_no_tagnum(type)
-
-#define setup(type) \
- unsigned int length; \
- setup_no_length(type)
-
-/* helper macros for cleanup */
-#define clean_return(val) { retval = val; goto error_out; }
-
-/* alloc_field is the first thing to allocate storage that may need cleanup */
-#define alloc_field(var) \
- var = calloc(1,sizeof(*var)); \
- if ((var) == NULL) clean_return(ENOMEM)
-
-/*
- * Allocate a principal and initialize enough fields for
- * krb5_free_principal to have defined behavior.
- */
-#define alloc_principal(var) \
- alloc_field(var); \
- var->realm.data = NULL; \
- var->data = NULL
-
-/* process encoding header ***************************************/
-/* decode tag and check that it == [APPLICATION tagnum] */
-#define check_apptag(tagexpect) \
- { \
- taginfo t1; \
- retval = asn1_get_tag_2(&buf, &t1); \
- if (retval) clean_return (retval); \
- if (t1.asn1class != APPLICATION || t1.construction != CONSTRUCTED) \
- clean_return(ASN1_BAD_ID); \
- if (t1.tagnum != (tagexpect)) clean_return(KRB5_BADMSGTYPE); \
- asn1class = t1.asn1class; \
- construction = t1.construction; \
- tagnum = t1.tagnum; \
- }
-
-
-
-/* process a structure *******************************************/
-
-/* decode an explicit tag and place the number in tagnum */
-#define next_tag_from_buf(buf) \
- { taginfo t2; \
- retval = asn1_get_tag_2(&(buf), &t2); \
- if (retval) clean_return(retval); \
- asn1class = t2.asn1class; \
- construction = t2.construction; \
- tagnum = t2.tagnum; \
- indef = t2.indef; \
- taglen = t2.length; \
- }
-#define next_tag() next_tag_from_buf(subbuf)
-
-
-static asn1_error_code
-asn1_get_eoc_tag (asn1buf *buf)
-{
- asn1_error_code retval;
- taginfo t;
-
- retval = asn1_get_tag_2(buf, &t);
- if (retval)
- return retval;
- if (t.asn1class != UNIVERSAL || t.tagnum || t.indef)
- return ASN1_MISSING_EOC;
- return 0;
-}
-
-#define get_eoc() \
- { \
- retval = asn1_get_eoc_tag(&subbuf); \
- if (retval) clean_return(retval); \
- }
-
-/* decode sequence header and initialize tagnum with the first field */
-#define begin_structure() \
- unsigned int taglen; \
- asn1buf subbuf; \
- int seqindef; \
- int indef; \
- retval = asn1_get_sequence(&buf,&length,&seqindef); \
- if (retval) clean_return(retval); \
- retval = asn1buf_imbed(&subbuf,&buf,length,seqindef); \
- if (retval) clean_return(retval); \
- next_tag()
-
-#define end_structure() \
- retval = asn1buf_sync(&buf,&subbuf,asn1class, \
- tagnum,length,indef,seqindef); \
- if (retval) clean_return(retval)
-
-/* process fields *******************************************/
-/* normal fields ************************/
-#define get_field_body(var,decoder) \
- retval = decoder(&subbuf,&(var)); \
- if (retval) clean_return(retval); \
- if (indef) { get_eoc(); } \
- next_tag()
-
-/*
- * error_if_bad_tag
- *
- * Checks that the next tag is the expected one; returns with an error
- * if not.
- */
-#define error_if_bad_tag(tagexpect) \
- if (tagnum != (tagexpect)) { clean_return ((tagnum < (tagexpect)) ? ASN1_MISPLACED_FIELD : ASN1_MISSING_FIELD); }
-
-/*
- * decode a field (<[UNIVERSAL id]> <length> <contents>)
- * check that the id number == tagexpect then
- * decode into var
- * get the next tag
- */
-#define get_field(var,tagexpect,decoder) \
- error_if_bad_tag(tagexpect); \
- if (asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED) \
- clean_return(ASN1_BAD_ID); \
- get_field_body(var,decoder)
-
-/* decode (or skip, if not present) an optional field */
-#define opt_field(var,tagexpect,decoder) \
- if (asn1buf_remains(&subbuf, seqindef)) { \
- if (asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED) \
- clean_return(ASN1_BAD_ID); \
- if (tagnum == (tagexpect)) { \
- get_field_body(var,decoder); \
- } \
- }
-
-/* field w/ accompanying length *********/
-#define get_lenfield_body(len,var,decoder) \
- retval = decoder(&subbuf,&(len),&(var)); \
- if (retval) clean_return(retval); \
- if (indef) { get_eoc(); } \
- next_tag()
-
-/* decode a field w/ its length (for string types) */
-#define get_lenfield(len,var,tagexpect,decoder) \
- error_if_bad_tag(tagexpect); \
- if (asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED) \
- clean_return(ASN1_BAD_ID); \
- get_lenfield_body(len,var,decoder)
-
-/* decode an optional field w/ length */
-#define opt_lenfield(len,var,tagexpect,decoder) \
- if (asn1buf_remains(&subbuf, seqindef)) { \
- if (asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED) \
- clean_return(ASN1_BAD_ID); \
- if (tagnum == (tagexpect)) { \
- get_lenfield_body(len,var,decoder); \
- } \
- }
-
-
-/* clean up ******************************************************/
-/* finish up */
-/* to make things less painful, assume the cleanup is passed rep */
-#define cleanup(cleanup_routine) \
- *repptr = rep; \
- return 0; \
-error_out: \
-if (rep) \
- cleanup_routine(rep); \
-return retval;
-
-#define cleanup_none() \
- *repptr = rep; \
- return 0; \
-error_out: \
-return retval;
-
-#define cleanup_manual() \
- *repptr = rep; \
- return 0;
-
-#define free_field(rep,f) free((rep)->f)
-#define clear_field(rep,f) (rep)->f = 0
+#include "krb5_decode_macros.h"
#ifndef LEAN_CLIENT
krb5_error_code
return retval;
}
-krb5_error_code
-decode_krb5_as_req(const krb5_data *code, krb5_kdc_req **repptr)
-{
- setup_no_length(krb5_kdc_req *);
- alloc_field(rep);
- clear_field(rep,padata);
- clear_field(rep,client);
- clear_field(rep,server);
- clear_field(rep,ktype);
- clear_field(rep,addresses);
- clear_field(rep,authorization_data.ciphertext.data);
- clear_field(rep,unenc_authdata);
- clear_field(rep,second_ticket);
- clear_field(rep, kdc_state);
-
- check_apptag(10);
- retval = asn1_decode_kdc_req(&buf,rep);
- if (retval) clean_return(retval);
-#ifdef KRB5_MSGTYPE_STRICT
- if (rep->msg_type != KRB5_AS_REQ) clean_return(KRB5_BADMSGTYPE);
-#endif
-
- cleanup_manual();
-error_out:
- krb5_free_kdc_req(NULL, rep);
- return retval;
-}
-
-krb5_error_code
-decode_krb5_tgs_req(const krb5_data *code, krb5_kdc_req **repptr)
-{
- setup_no_length(krb5_kdc_req *);
- alloc_field(rep);
- clear_field(rep,padata);
- clear_field(rep,client);
- clear_field(rep,server);
- clear_field(rep,ktype);
- clear_field(rep,addresses);
- clear_field(rep,authorization_data.ciphertext.data);
- clear_field(rep,unenc_authdata);
- clear_field(rep,second_ticket);
- clear_field(rep, kdc_state);
-
- check_apptag(12);
- retval = asn1_decode_kdc_req(&buf,rep);
- if (retval) clean_return(retval);
-#ifdef KRB5_MSGTYPE_STRICT
- if (rep->msg_type != KRB5_TGS_REQ) clean_return(KRB5_BADMSGTYPE);
-#endif
-
- cleanup_manual();
-error_out:
- krb5_free_kdc_req(NULL, rep);
- return retval;
-}
-
-krb5_error_code
-decode_krb5_kdc_req_body(const krb5_data *code, krb5_kdc_req **repptr)
-{
- setup_buf_only(krb5_kdc_req *);
- alloc_field(rep);
-
- retval = asn1_decode_kdc_req_body(&buf,rep);
- if (retval) clean_return(retval);
-
- cleanup(free);
-}
-
/*
* decode_krb5_safe_with_body
*
cleanup(free);
}
-krb5_error_code decode_krb5_pa_fx_fast_request
-(const krb5_data *code, krb5_fast_armored_req **repptr)
-{
- setup(krb5_fast_armored_req *);
- alloc_field(rep);
- clear_field(rep, armor);
- {
- int indef;
- unsigned int taglen;
- next_tag_from_buf(buf);
- if (tagnum != 0)
- clean_return(ASN1_BAD_ID);
- }
- {begin_structure();
- opt_field(rep->armor, 0, asn1_decode_fast_armor_ptr);
- get_field(rep->req_checksum, 1, asn1_decode_checksum);
- get_field(rep->enc_part, 2, asn1_decode_encrypted_data);
- end_structure();}
- rep->magic = KV5M_FAST_ARMORED_REQ;
- cleanup(free);
-}
-
-krb5_error_code decode_krb5_fast_req
-(const krb5_data *code, krb5_fast_req **repptr)
-{
- setup(krb5_fast_req *);
- alloc_field(rep);
- alloc_field(rep->req_body);
- clear_field(rep, req_body->padata);
- {begin_structure();
- get_field(rep->fast_options, 0, asn1_decode_krb5_flags);
- opt_field(rep->req_body->padata, 1, asn1_decode_sequence_of_pa_data);
- get_field(*(rep->req_body), 2, asn1_decode_kdc_req_body);
- end_structure(); }
- rep->magic = KV5M_FAST_REQ;
- cleanup_manual();
-error_out:
- if (rep) {
- if (rep->req_body)
- krb5_free_kdc_req(0, rep->req_body);
- free(rep);
- }
- return retval;
-}
-
-krb5_error_code decode_krb5_fast_response
-(const krb5_data *code, krb5_fast_response **repptr)
+krb5_error_code
+decode_krb5_fast_response(const krb5_data *code, krb5_fast_response **repptr)
{
setup(krb5_fast_response *);
cleanup(free);
}
-krb5_error_code decode_krb5_pa_fx_fast_reply
-(const krb5_data *code, krb5_enc_data **repptr)
+krb5_error_code
+decode_krb5_pa_fx_fast_reply(const krb5_data *code, krb5_enc_data **repptr)
{
setup(krb5_enc_data *);
alloc_field(rep);
cleanup(free);
}
-krb5_error_code decode_krb5_iakerb_header
-(const krb5_data *code, krb5_iakerb_header **repptr)
+krb5_error_code
+decode_krb5_iakerb_header(const krb5_data *code, krb5_iakerb_header **repptr)
{
setup_buf_only(krb5_iakerb_header *);
alloc_field(rep);
cleanup(free);
}
-krb5_error_code decode_krb5_iakerb_finished
-(const krb5_data *code, krb5_iakerb_finished **repptr)
+krb5_error_code
+decode_krb5_iakerb_finished(const krb5_data *code, krb5_iakerb_finished **repptr)
{
setup_buf_only(krb5_iakerb_finished *);
alloc_field(rep);
}
#ifndef DISABLE_PKINIT
-krb5_error_code
-decode_krb5_pa_pk_as_req(const krb5_data *code, krb5_pa_pk_as_req **repptr)
-{
- setup_buf_only(krb5_pa_pk_as_req *);
- alloc_field(rep);
-
- retval = asn1_decode_pa_pk_as_req(&buf, rep);
- if (retval) clean_return(retval);
-
- cleanup(free);
-}
-
-krb5_error_code
-decode_krb5_pa_pk_as_req_draft9(const krb5_data *code,
- krb5_pa_pk_as_req_draft9 **repptr)
-{
- setup_buf_only(krb5_pa_pk_as_req_draft9 *);
- alloc_field(rep);
-
- retval = asn1_decode_pa_pk_as_req_draft9(&buf, rep);
- if (retval) clean_return(retval);
-
- cleanup(free);
-}
krb5_error_code
decode_krb5_pa_pk_as_rep(const krb5_data *code, krb5_pa_pk_as_rep **repptr)
--- /dev/null
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * src/lib/krb5/asn.1/krb5_decode_kdc.c
+ *
+ * Copyright 1994, 2008. 2010 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "k5-int.h"
+#include "krbasn1.h"
+#include "krb5_decode_macros.h"
+
+krb5_error_code
+decode_krb5_as_req(const krb5_data *code, krb5_kdc_req **repptr)
+{
+ setup_no_length(krb5_kdc_req *);
+ alloc_field(rep);
+ clear_field(rep,padata);
+ clear_field(rep,client);
+ clear_field(rep,server);
+ clear_field(rep,ktype);
+ clear_field(rep,addresses);
+ clear_field(rep,authorization_data.ciphertext.data);
+ clear_field(rep,unenc_authdata);
+ clear_field(rep,second_ticket);
+ clear_field(rep, kdc_state);
+
+ check_apptag(10);
+ retval = asn1_decode_kdc_req(&buf,rep);
+ if (retval) clean_return(retval);
+#ifdef KRB5_MSGTYPE_STRICT
+ if (rep->msg_type != KRB5_AS_REQ) clean_return(KRB5_BADMSGTYPE);
+#endif
+
+ cleanup_manual();
+error_out:
+ krb5_free_kdc_req(NULL, rep);
+ return retval;
+}
+
+krb5_error_code
+decode_krb5_tgs_req(const krb5_data *code, krb5_kdc_req **repptr)
+{
+ setup_no_length(krb5_kdc_req *);
+ alloc_field(rep);
+ clear_field(rep,padata);
+ clear_field(rep,client);
+ clear_field(rep,server);
+ clear_field(rep,ktype);
+ clear_field(rep,addresses);
+ clear_field(rep,authorization_data.ciphertext.data);
+ clear_field(rep,unenc_authdata);
+ clear_field(rep,second_ticket);
+ clear_field(rep, kdc_state);
+
+ check_apptag(12);
+ retval = asn1_decode_kdc_req(&buf,rep);
+ if (retval) clean_return(retval);
+#ifdef KRB5_MSGTYPE_STRICT
+ if (rep->msg_type != KRB5_TGS_REQ) clean_return(KRB5_BADMSGTYPE);
+#endif
+
+ cleanup_manual();
+error_out:
+ krb5_free_kdc_req(NULL, rep);
+ return retval;
+}
+
+krb5_error_code
+decode_krb5_kdc_req_body(const krb5_data *code, krb5_kdc_req **repptr)
+{
+ setup_buf_only(krb5_kdc_req *);
+ alloc_field(rep);
+
+ retval = asn1_decode_kdc_req_body(&buf,rep);
+ if (retval) clean_return(retval);
+
+ cleanup(free);
+}
+
+krb5_error_code
+decode_krb5_fast_req(const krb5_data *code, krb5_fast_req **repptr)
+{
+ setup(krb5_fast_req *);
+ alloc_field(rep);
+ alloc_field(rep->req_body);
+ clear_field(rep, req_body->padata);
+ {begin_structure();
+ get_field(rep->fast_options, 0, asn1_decode_krb5_flags);
+ opt_field(rep->req_body->padata, 1, asn1_decode_sequence_of_pa_data);
+ get_field(*(rep->req_body), 2, asn1_decode_kdc_req_body);
+ end_structure(); }
+ rep->magic = KV5M_FAST_REQ;
+ cleanup_manual();
+error_out:
+ if (rep) {
+ if (rep->req_body)
+ krb5_free_kdc_req(0, rep->req_body);
+ free(rep);
+ }
+ return retval;
+}
+
+krb5_error_code
+decode_krb5_pa_fx_fast_request(const krb5_data *code, krb5_fast_armored_req **repptr)
+{
+ setup(krb5_fast_armored_req *);
+ alloc_field(rep);
+ clear_field(rep, armor);
+ {
+ int indef;
+ unsigned int taglen;
+ next_tag_from_buf(buf);
+ if (tagnum != 0)
+ clean_return(ASN1_BAD_ID);
+ }
+ {begin_structure();
+ opt_field(rep->armor, 0, asn1_decode_fast_armor_ptr);
+ get_field(rep->req_checksum, 1, asn1_decode_checksum);
+ get_field(rep->enc_part, 2, asn1_decode_encrypted_data);
+ end_structure();}
+ rep->magic = KV5M_FAST_ARMORED_REQ;
+ cleanup(free);
+}
+
+#ifndef DISABLE_PKINIT
+krb5_error_code
+decode_krb5_pa_pk_as_req(const krb5_data *code, krb5_pa_pk_as_req **repptr)
+{
+ setup_buf_only(krb5_pa_pk_as_req *);
+ alloc_field(rep);
+
+ retval = asn1_decode_pa_pk_as_req(&buf, rep);
+ if (retval) clean_return(retval);
+
+ cleanup(free);
+}
+
+krb5_error_code
+decode_krb5_pa_pk_as_req_draft9(const krb5_data *code,
+ krb5_pa_pk_as_req_draft9 **repptr)
+{
+ setup_buf_only(krb5_pa_pk_as_req_draft9 *);
+ alloc_field(rep);
+
+ retval = asn1_decode_pa_pk_as_req_draft9(&buf, rep);
+ if (retval) clean_return(retval);
+
+ cleanup(free);
+}
+#endif /* DISABLE_PKINIT */
+
--- /dev/null
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * src/lib/krb5/asn.1/krb5_decode_macros.h
+ *
+ * Copyright 1994, 2008 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifndef KRB5_DECODE_MACROS_H
+#define KRB5_DECODE_MACROS_H
+
+#include "asn1_k_decode.h"
+#include "asn1_decode.h"
+#include "asn1_get.h"
+#include "asn1_misc.h"
+
+/* setup *********************************************************/
+/* set up variables */
+/*
+ * the setup* macros can return, but are always used at function start
+ * and thus need no malloc cleanup
+ */
+#define setup_buf_only(type) \
+ asn1_error_code retval; \
+ asn1buf buf; \
+ type rep = NULL; \
+ \
+ *repptr = NULL; \
+ retval = asn1buf_wrap_data(&buf,code); \
+ if (retval) return retval
+
+#define setup_no_tagnum(type) \
+ asn1_class asn1class; \
+ asn1_construction construction; \
+ setup_buf_only(type)
+
+#define setup_no_length(type) \
+ asn1_tagnum tagnum; \
+ setup_no_tagnum(type)
+
+#define setup(type) \
+ unsigned int length; \
+ setup_no_length(type)
+
+/* helper macros for cleanup */
+#define clean_return(val) { retval = val; goto error_out; }
+
+/* alloc_field is the first thing to allocate storage that may need cleanup */
+#define alloc_field(var) \
+ var = calloc(1,sizeof(*var)); \
+ if ((var) == NULL) clean_return(ENOMEM)
+
+/*
+ * Allocate a principal and initialize enough fields for
+ * krb5_free_principal to have defined behavior.
+ */
+#define alloc_principal(var) \
+ alloc_field(var); \
+ var->realm.data = NULL; \
+ var->data = NULL
+
+/* process encoding header ***************************************/
+/* decode tag and check that it == [APPLICATION tagnum] */
+#define check_apptag(tagexpect) \
+ { \
+ taginfo t1; \
+ retval = asn1_get_tag_2(&buf, &t1); \
+ if (retval) clean_return (retval); \
+ if (t1.asn1class != APPLICATION || t1.construction != CONSTRUCTED) \
+ clean_return(ASN1_BAD_ID); \
+ if (t1.tagnum != (tagexpect)) clean_return(KRB5_BADMSGTYPE); \
+ asn1class = t1.asn1class; \
+ construction = t1.construction; \
+ tagnum = t1.tagnum; \
+ }
+
+
+
+/* process a structure *******************************************/
+
+/* decode an explicit tag and place the number in tagnum */
+#define next_tag_from_buf(buf) \
+ { taginfo t2; \
+ retval = asn1_get_tag_2(&(buf), &t2); \
+ if (retval) clean_return(retval); \
+ asn1class = t2.asn1class; \
+ construction = t2.construction; \
+ tagnum = t2.tagnum; \
+ indef = t2.indef; \
+ taglen = t2.length; \
+ }
+#define next_tag() next_tag_from_buf(subbuf)
+
+
+static asn1_error_code
+asn1_get_eoc_tag (asn1buf *buf)
+{
+ asn1_error_code retval;
+ taginfo t;
+
+ retval = asn1_get_tag_2(buf, &t);
+ if (retval)
+ return retval;
+ if (t.asn1class != UNIVERSAL || t.tagnum || t.indef)
+ return ASN1_MISSING_EOC;
+ return 0;
+}
+
+#define get_eoc() \
+ { \
+ retval = asn1_get_eoc_tag(&subbuf); \
+ if (retval) clean_return(retval); \
+ }
+
+/* decode sequence header and initialize tagnum with the first field */
+#define begin_structure() \
+ unsigned int taglen; \
+ asn1buf subbuf; \
+ int seqindef; \
+ int indef; \
+ retval = asn1_get_sequence(&buf,&length,&seqindef); \
+ if (retval) clean_return(retval); \
+ retval = asn1buf_imbed(&subbuf,&buf,length,seqindef); \
+ if (retval) clean_return(retval); \
+ next_tag()
+
+#define end_structure() \
+ retval = asn1buf_sync(&buf,&subbuf,asn1class, \
+ tagnum,length,indef,seqindef); \
+ if (retval) clean_return(retval)
+
+/* process fields *******************************************/
+/* normal fields ************************/
+#define get_field_body(var,decoder) \
+ retval = decoder(&subbuf,&(var)); \
+ if (retval) clean_return(retval); \
+ if (indef) { get_eoc(); } \
+ next_tag()
+
+/*
+ * error_if_bad_tag
+ *
+ * Checks that the next tag is the expected one; returns with an error
+ * if not.
+ */
+#define error_if_bad_tag(tagexpect) \
+ if (tagnum != (tagexpect)) { clean_return ((tagnum < (tagexpect)) ? ASN1_MISPLACED_FIELD : ASN1_MISSING_FIELD); }
+
+/*
+ * decode a field (<[UNIVERSAL id]> <length> <contents>)
+ * check that the id number == tagexpect then
+ * decode into var
+ * get the next tag
+ */
+#define get_field(var,tagexpect,decoder) \
+ error_if_bad_tag(tagexpect); \
+ if (asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED) \
+ clean_return(ASN1_BAD_ID); \
+ get_field_body(var,decoder)
+
+/* decode (or skip, if not present) an optional field */
+#define opt_field(var,tagexpect,decoder) \
+ if (asn1buf_remains(&subbuf, seqindef)) { \
+ if (asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED) \
+ clean_return(ASN1_BAD_ID); \
+ if (tagnum == (tagexpect)) { \
+ get_field_body(var,decoder); \
+ } \
+ }
+
+/* field w/ accompanying length *********/
+#define get_lenfield_body(len,var,decoder) \
+ retval = decoder(&subbuf,&(len),&(var)); \
+ if (retval) clean_return(retval); \
+ if (indef) { get_eoc(); } \
+ next_tag()
+
+/* decode a field w/ its length (for string types) */
+#define get_lenfield(len,var,tagexpect,decoder) \
+ error_if_bad_tag(tagexpect); \
+ if (asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED) \
+ clean_return(ASN1_BAD_ID); \
+ get_lenfield_body(len,var,decoder)
+
+/* decode an optional field w/ length */
+#define opt_lenfield(len,var,tagexpect,decoder) \
+ if (asn1buf_remains(&subbuf, seqindef)) { \
+ if (asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED) \
+ clean_return(ASN1_BAD_ID); \
+ if (tagnum == (tagexpect)) { \
+ get_lenfield_body(len,var,decoder); \
+ } \
+ }
+
+
+/* clean up ******************************************************/
+/* finish up */
+/* to make things less painful, assume the cleanup is passed rep */
+#define cleanup(cleanup_routine) \
+ *repptr = rep; \
+ return 0; \
+error_out: \
+if (rep) \
+ cleanup_routine(rep); \
+return retval;
+
+#define cleanup_none() \
+ *repptr = rep; \
+ return 0; \
+error_out: \
+return retval;
+
+#define cleanup_manual() \
+ *repptr = rep; \
+ return 0;
+
+#define free_field(rep,f) free((rep)->f)
+#define clear_field(rep,f) (rep)->f = 0
+
+#endif