From: Zhanna Tsitkov Date: Tue, 11 Jan 2011 20:00:52 +0000 (+0000) Subject: Asn.1 decode related file rearrangement. It was made based on the following criteria: X-Git-Tag: krb5-1.10-alpha1~621 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=459fcc3b51042bfe2a662a3afe261f359b26181b;p=krb5.git Asn.1 decode related file rearrangement. It was made based on the following criteria: 1. based on functionality (for example, kdc-only code) 2. Well defined clusters of functions (fast, sam). git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@24593 dc483132-0cff-0310-8789-dd5450dbe970 --- diff --git a/src/lib/krb5/asn.1/Makefile.in b/src/lib/krb5/asn.1/Makefile.in index ec8455ca6..43a4bdd7d 100644 --- a/src/lib/krb5/asn.1/Makefile.in +++ b/src/lib/krb5/asn.1/Makefile.in @@ -11,11 +11,15 @@ EHDRDIR=$(BUILDTOP)/include/krb5/asn.1 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\ @@ -24,11 +28,15 @@ STLIBOBJS= \ 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\ @@ -37,11 +45,15 @@ SRCS= \ 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)\ diff --git a/src/lib/krb5/asn.1/asn1_k_decode.c b/src/lib/krb5/asn.1/asn1_k_decode.c index c2dd5f6d4..365d18aaf 100644 --- a/src/lib/krb5/asn.1/asn1_k_decode.c +++ b/src/lib/krb5/asn.1/asn1_k_decode.c @@ -26,369 +26,21 @@ */ #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 @@ -405,37 +57,6 @@ asn1_decode_kerberos_time(asn1buf *buf, krb5_timestamp *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; \ - } -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) { @@ -731,99 +352,6 @@ asn1_decode_ticket_ptr(asn1buf *buf, krb5_ticket **valptr) 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) { @@ -1428,251 +956,6 @@ asn1_decode_sequence_of_passwdsequence(asn1buf *buf, 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) @@ -1779,56 +1062,6 @@ error_out: 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) { @@ -1999,31 +1232,6 @@ asn1_decode_sequence_of_external_principal_identifier( 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) @@ -2115,7 +1323,7 @@ error_out: 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) @@ -2140,39 +1348,6 @@ asn1_decode_sequence_of_trusted_ca(asn1buf *buf, krb5_trusted_ca ***val) 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) { @@ -2442,113 +1617,6 @@ error_out: 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) { diff --git a/src/lib/krb5/asn.1/asn1_k_decode_fast.c b/src/lib/krb5/asn.1/asn1_k_decode_fast.c new file mode 100644 index 000000000..8007371bc --- /dev/null +++ b/src/lib/krb5/asn.1/asn1_k_decode_fast.c @@ -0,0 +1,80 @@ +/* -*- 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); +} + diff --git a/src/lib/krb5/asn.1/asn1_k_decode_kdc.c b/src/lib/krb5/asn.1/asn1_k_decode_kdc.c new file mode 100644 index 000000000..d8499bb7a --- /dev/null +++ b/src/lib/krb5/asn.1/asn1_k_decode_kdc.c @@ -0,0 +1,309 @@ +/* -*- 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 */ diff --git a/src/lib/krb5/asn.1/asn1_k_decode_macros.h b/src/lib/krb5/asn.1/asn1_k_decode_macros.h new file mode 100644 index 000000000..24580af66 --- /dev/null +++ b/src/lib/krb5/asn.1/asn1_k_decode_macros.h @@ -0,0 +1,415 @@ +/* -*- 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 diff --git a/src/lib/krb5/asn.1/asn1_k_decode_sam.c b/src/lib/krb5/asn.1/asn1_k_decode_sam.c new file mode 100644 index 000000000..083e5435c --- /dev/null +++ b/src/lib/krb5/asn.1/asn1_k_decode_sam.c @@ -0,0 +1,274 @@ +/* -*- 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; +} + diff --git a/src/lib/krb5/asn.1/deps b/src/lib/krb5/asn.1/deps index d000c39e5..8b90f7796 100644 --- a/src/lib/krb5/asn.1/deps +++ b/src/lib/krb5/asn.1/deps @@ -26,6 +26,45 @@ asn1_k_decode.so asn1_k_decode.po $(OUTPRE)asn1_k_decode.$(OBJEXT): \ $(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 \ diff --git a/src/lib/krb5/asn.1/krb5_decode.c b/src/lib/krb5/asn.1/krb5_decode.c index af5c65928..0fa8e0434 100644 --- a/src/lib/krb5/asn.1/krb5_decode.c +++ b/src/lib/krb5/asn.1/krb5_decode.c @@ -30,209 +30,7 @@ #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]> ) - * 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 @@ -511,74 +309,6 @@ error_out: 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 * @@ -1110,53 +840,8 @@ decode_krb5_etype_list(const krb5_data *code, krb5_etype_list **repptr) 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 *); @@ -1174,8 +859,8 @@ krb5_error_code decode_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); @@ -1218,8 +903,8 @@ decode_krb5_ad_signedpath(const krb5_data *code, krb5_ad_signedpath **repptr) 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); @@ -1230,8 +915,8 @@ krb5_error_code decode_krb5_iakerb_header 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); @@ -1267,30 +952,6 @@ krb5int_get_authdata_containee_types(krb5_context context, } #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) diff --git a/src/lib/krb5/asn.1/krb5_decode_kdc.c b/src/lib/krb5/asn.1/krb5_decode_kdc.c new file mode 100644 index 000000000..e888d71aa --- /dev/null +++ b/src/lib/krb5/asn.1/krb5_decode_kdc.c @@ -0,0 +1,171 @@ +/* -*- 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 */ + diff --git a/src/lib/krb5/asn.1/krb5_decode_macros.h b/src/lib/krb5/asn.1/krb5_decode_macros.h new file mode 100644 index 000000000..a77e74bac --- /dev/null +++ b/src/lib/krb5/asn.1/krb5_decode_macros.h @@ -0,0 +1,239 @@ +/* -*- 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]> ) + * 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