/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
* Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
*/
/*
* src/lib/krb5/asn.1/asn1_k_decode.c
*
* Copyright 1994, 2007, 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.
*/
#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;
/* scalars */
asn1_error_code
asn1_decode_kerberos_time(asn1buf *buf, krb5_timestamp *val)
{
time_t t;
asn1_error_code retval;
retval = asn1_decode_generaltime(buf,&t);
if (retval)
return retval;
*val = t;
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)
{
asn1_error_code retval;
unsigned long n;
retval = asn1_decode_maybe_unsigned(buf, &n);
if (retval) return retval;
*val = (krb5_ui_4)n & 0xffffffff;
return 0;
}
asn1_error_code
asn1_decode_msgtype(asn1buf *buf, krb5_msgtype *val)
{
asn1_error_code retval;
unsigned long n;
retval = asn1_decode_unsigned_integer(buf,&n);
if (retval) return retval;
*val = (krb5_msgtype) n;
return 0;
}
/* structures */
asn1_error_code
asn1_decode_realm(asn1buf *buf, krb5_principal *val)
{
return asn1_decode_generalstring(buf,
&((*val)->realm.length),
&((*val)->realm.data));
}
asn1_error_code
asn1_decode_principal_name(asn1buf *buf, krb5_principal *val)
{
int size = 0, i;
krb5_data *array = NULL, *new_array;
setup();
{ begin_structure();
get_field((*val)->type,0,asn1_decode_int32);
{ sequence_of_no_tagvars(&subbuf);
while (asn1buf_remains(&seqbuf,seqofindef) > 0) {
unsigned int len;
char *str;
new_array = realloc(array, (size + 1) * sizeof(krb5_data));
if (new_array == NULL) clean_return(ENOMEM);
array = new_array;
retval = asn1_decode_generalstring(&seqbuf, &len, &str);
if (retval) clean_return(retval);
array[size].data = str;
array[size].length = len;
size++;
}
end_sequence_of_no_tagvars(&subbuf);
}
if (indef) {
get_eoc();
}
next_tag();
end_structure();
}
(*val)->data = array;
(*val)->length = size;
(*val)->magic = KV5M_PRINCIPAL;
return 0;
error_out:
for (i = 0; i < size; i++)
free(array[i].data);
free(array);
return retval;
}
asn1_error_code
asn1_decode_checksum(asn1buf *buf, krb5_checksum *val)
{
setup();
val->contents = NULL;
{ begin_structure();
get_field(val->checksum_type,0,asn1_decode_cksumtype);
get_lenfield(val->length,val->contents,1,asn1_decode_octetstring);
end_structure();
val->magic = KV5M_CHECKSUM;
}
return 0;
error_out:
free(val->contents);
return retval;
}
asn1_error_code
asn1_decode_checksum_ptr(asn1buf *buf, krb5_checksum **valptr)
{
decode_ptr(krb5_checksum *, asn1_decode_checksum);
}
asn1_error_code
asn1_decode_encryption_key(asn1buf *buf, krb5_keyblock *val)
{
setup();
val->contents = NULL;
{ begin_structure();
get_field(val->enctype,0,asn1_decode_enctype);
get_lenfield(val->length,val->contents,1,asn1_decode_octetstring);
end_structure();
val->magic = KV5M_KEYBLOCK;
}
return 0;
error_out:
free(val->contents);
return retval;
}
asn1_error_code
asn1_decode_encryption_key_ptr(asn1buf *buf, krb5_keyblock **valptr)
{
decode_ptr(krb5_keyblock *, asn1_decode_encryption_key);
}
asn1_error_code
asn1_decode_encrypted_data(asn1buf *buf, krb5_enc_data *val)
{
setup();
val->ciphertext.data = NULL;
{ begin_structure();
get_field(val->enctype,0,asn1_decode_enctype);
opt_field(val->kvno,1,asn1_decode_kvno,0);
get_lenfield(val->ciphertext.length,val->ciphertext.data,2,asn1_decode_charstring);
end_structure();
val->magic = KV5M_ENC_DATA;
}
return 0;
error_out:
free(val->ciphertext.data);
val->ciphertext.data = NULL;
return retval;
}
asn1_error_code
asn1_decode_krb5_flags(asn1buf *buf, krb5_flags *val)
{
asn1_error_code retval;
asn1_octet unused, o;
taginfo t;
unsigned int i;
krb5_flags f=0;
unsigned int length;
retval = asn1_get_tag_2(buf, &t);
if (retval) return retval;
if (t.asn1class != UNIVERSAL || t.construction != PRIMITIVE ||
t.tagnum != ASN1_BITSTRING)
return ASN1_BAD_ID;
length = t.length;
retval = asn1buf_remove_octet(buf,&unused); /* # of padding bits */
if (retval) return retval;
/* Number of unused bits must be between 0 and 7. */
if (unused > 7) return ASN1_BAD_FORMAT;
length--;
for (i = 0; i < length; i++) {
retval = asn1buf_remove_octet(buf,&o);
if (retval) return retval;
/* ignore bits past number 31 */
if (i < 4)
f = (f<<8) | ((krb5_flags)o&0xFF);
}
if (length <= 4) {
/* Mask out unused bits, but only if necessary. */
f &= ~(krb5_flags)0 << unused;
}
/* left-justify */
if (length < 4)
f <<= (4 - length) * 8;
*val = f;
return 0;
}
asn1_error_code
asn1_decode_ticket_flags(asn1buf *buf, krb5_flags *val)
{ return asn1_decode_krb5_flags(buf,val); }
asn1_error_code
asn1_decode_ap_options(asn1buf *buf, krb5_flags *val)
{ return asn1_decode_krb5_flags(buf,val); }
asn1_error_code
asn1_decode_kdc_options(asn1buf *buf, krb5_flags *val)
{ return asn1_decode_krb5_flags(buf,val); }
asn1_error_code
asn1_decode_transited_encoding(asn1buf *buf, krb5_transited *val)
{
setup();
val->tr_contents.data = NULL;
{ begin_structure();
get_field(val->tr_type,0,asn1_decode_octet);
get_lenfield(val->tr_contents.length,val->tr_contents.data,1,asn1_decode_charstring);
end_structure();
val->magic = KV5M_TRANSITED;
}
return 0;
error_out:
krb5_free_data_contents(NULL, &val->tr_contents);
return retval;
}
asn1_error_code
asn1_decode_enc_kdc_rep_part(asn1buf *buf, krb5_enc_kdc_rep_part *val)
{
setup();
val->session = NULL;
val->last_req = NULL;
val->server = NULL;
val->caddrs = NULL;
val->enc_padata = NULL;
{ begin_structure();
get_field(val->session,0,asn1_decode_encryption_key_ptr);
get_field(val->last_req,1,asn1_decode_last_req);
get_field(val->nonce,2,asn1_decode_int32);
opt_field(val->key_exp,3,asn1_decode_kerberos_time,0);
get_field(val->flags,4,asn1_decode_ticket_flags);
get_field(val->times.authtime,5,asn1_decode_kerberos_time);
/* Set to authtime if missing */
opt_field(val->times.starttime,6,asn1_decode_kerberos_time,val->times.authtime);
get_field(val->times.endtime,7,asn1_decode_kerberos_time);
opt_field(val->times.renew_till,8,asn1_decode_kerberos_time,0);
alloc_principal(val->server);
get_field(val->server,9,asn1_decode_realm);
get_field(val->server,10,asn1_decode_principal_name);
opt_field(val->caddrs,11,asn1_decode_host_addresses,NULL);
opt_field(val->enc_padata,12,asn1_decode_sequence_of_pa_data,NULL);
end_structure();
val->magic = KV5M_ENC_KDC_REP_PART;
}
return 0;
error_out:
krb5_free_keyblock(NULL, val->session);
krb5_free_last_req(NULL, val->last_req);
krb5_free_principal(NULL, val->server);
krb5_free_addresses(NULL, val->caddrs);
krb5_free_pa_data(NULL, val->enc_padata);
val->session = NULL;
val->last_req = NULL;
val->server = NULL;
val->caddrs = NULL;
return retval;
}
asn1_error_code
asn1_decode_ticket(asn1buf *buf, krb5_ticket *val)
{
setup();
unsigned int applen;
apptag(1);
val->server = NULL;
val->enc_part.ciphertext.data = NULL;
val->enc_part2 = NULL;
{ begin_structure();
{ krb5_kvno vno;
get_field(vno,0,asn1_decode_kvno);
if (vno != KVNO) clean_return(KRB5KDC_ERR_BAD_PVNO); }
alloc_principal(val->server);
get_field(val->server,1,asn1_decode_realm);
get_field(val->server,2,asn1_decode_principal_name);
get_field(val->enc_part,3,asn1_decode_encrypted_data);
end_structure();
val->magic = KV5M_TICKET;
}
if (!applen) {
taginfo t;
retval = asn1_get_tag_2(buf, &t);
if (retval) clean_return(retval);
}
return 0;
error_out:
krb5_free_principal(NULL, val->server);
krb5_free_data_contents(NULL, &val->enc_part.ciphertext);
val->server = NULL;
return retval;
}
asn1_error_code
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)
{
setup();
val->user_data.data = NULL;
val->r_address = NULL;
val->s_address = NULL;
val->checksum = NULL;
{ begin_structure();
get_lenfield(val->user_data.length,val->user_data.data,0,asn1_decode_charstring);
opt_field(val->timestamp,1,asn1_decode_kerberos_time,0);
opt_field(val->usec,2,asn1_decode_int32,0);
opt_field(val->seq_number,3,asn1_decode_seqnum,0);
get_field(val->s_address,4,asn1_decode_host_address_ptr);
if (tagnum == 5) {
get_field(val->r_address,5,asn1_decode_host_address_ptr);
}
end_structure();
val->magic = KV5M_SAFE;
}
return 0;
error_out:
krb5_free_data_contents(NULL, &val->user_data);
krb5_free_address(NULL, val->r_address);
krb5_free_address(NULL, val->s_address);
val->r_address = NULL;
val->s_address = NULL;
return retval;
}
asn1_error_code
asn1_decode_host_address(asn1buf *buf, krb5_address *val)
{
setup();
val->contents = NULL;
{ begin_structure();
get_field(val->addrtype,0,asn1_decode_addrtype);
get_lenfield(val->length,val->contents,1,asn1_decode_octetstring);
end_structure();
val->magic = KV5M_ADDRESS;
}
return 0;
error_out:
free(val->contents);
val->contents = NULL;
return retval;
}
asn1_error_code
asn1_decode_host_address_ptr(asn1buf *buf, krb5_address **valptr)
{
decode_ptr(krb5_address *, asn1_decode_host_address);
}
asn1_error_code
asn1_decode_kdc_rep(asn1buf *buf, krb5_kdc_rep *val)
{
setup();
val->padata = NULL;
val->client = NULL;
val->ticket = NULL;
val->enc_part.ciphertext.data = NULL;
val->enc_part2 = NULL;
{ begin_structure();
{ krb5_kvno pvno;
get_field(pvno,0,asn1_decode_kvno);
if (pvno != KVNO) clean_return(KRB5KDC_ERR_BAD_PVNO); }
get_field(val->msg_type,1,asn1_decode_msgtype);
opt_field(val->padata,2,asn1_decode_sequence_of_pa_data,NULL);
alloc_principal(val->client);
get_field(val->client,3,asn1_decode_realm);
get_field(val->client,4,asn1_decode_principal_name);
get_field(val->ticket,5,asn1_decode_ticket_ptr);
get_field(val->enc_part,6,asn1_decode_encrypted_data);
end_structure();
val->magic = KV5M_KDC_REP;
}
return 0;
error_out:
krb5_free_pa_data(NULL, val->padata);
krb5_free_principal(NULL, val->client);
krb5_free_ticket(NULL, val->ticket);
krb5_free_data_contents(NULL, &val->enc_part.ciphertext);
val->padata = NULL;
val->client = NULL;
val->ticket = NULL;
val->enc_part.ciphertext.data = NULL;
return retval;
}
/* arrays */
#define get_element(element,decoder) \
retval = decoder(&seqbuf,&element); \
if (retval) clean_return(retval)
static void *
array_expand (void *array, int n_elts, size_t elt_size)
{
size_t new_size;
if (n_elts <= 0)
return NULL;
if ((unsigned int) n_elts > SIZE_MAX / elt_size)
return NULL;
new_size = n_elts * elt_size;
if (new_size == 0)
return NULL;
if (new_size / elt_size != (unsigned int) n_elts)
return NULL;
return realloc(array, new_size);
}
#define array_append(array,size,element,type) \
{ \
void *new_array = array_expand(*(array), (size)+2, sizeof(type*)); \
if (new_array == NULL) clean_return(ENOMEM); \
*(array) = new_array; \
(*(array))[(size)++] = elt; \
}
/*
* Function body for array decoders. freefn is expected to look like
* a krb5_free_ function, so we pass a null first argument.
*/
#define decode_array_body(type,decoder,freefn) \
asn1_error_code retval; \
type *elt = NULL, **array; \
int size = 0, i; \
\
array = *val = NULL; \
{ sequence_of(buf); \
while (asn1buf_remains(&seqbuf,seqofindef) > 0) { \
get_element(elt,decoder); \
array_append(&array,size,elt,type); \
elt = NULL; \
} \
if (array == NULL) \
array = malloc(sizeof(type*)); \
/* Solaris Kerberos */ \
if (array == NULL) { \
retval = ENOMEM; \
goto error_out; \
} \
array[size] = NULL; \
end_sequence_of(buf); \
} \
*val = array; \
return 0; \
error_out: \
if (elt) \
freefn(NULL,elt); \
if (array) /* Solaris Kerberos */ \
for (i = 0; i < size; i++) \
freefn(NULL,array[i]); \
free(array); \
return retval
static void
free_authdata_elt(void *dummy, krb5_authdata *val)
{
free(val->contents);
free(val);
}
asn1_error_code
asn1_decode_authorization_data(asn1buf *buf, krb5_authdata ***val)
{
decode_array_body(krb5_authdata,asn1_decode_authdata_elt_ptr,
free_authdata_elt);
}
asn1_error_code
asn1_decode_authdata_elt(asn1buf *buf, krb5_authdata *val)
{
setup();
val->contents = NULL;
{ begin_structure();
get_field(val->ad_type,0,asn1_decode_authdatatype);
get_lenfield(val->length,val->contents,1,asn1_decode_octetstring);
end_structure();
val->magic = KV5M_AUTHDATA;
}
return 0;
error_out:
free(val->contents);
val->contents = NULL;
return retval;
}
static asn1_error_code
asn1_peek_authdata_elt(asn1buf *buf, krb5_authdatatype *val)
{
setup();
*val = 0;
{ begin_structure();
get_field(*val, 0, asn1_decode_authdatatype);
end_structure();
}
return 0;
error_out:
return retval;
}
asn1_error_code
asn1_peek_authorization_data(asn1buf *buf, unsigned int *num,
krb5_authdatatype **val)
{
int size = 0;
krb5_authdatatype *array = NULL, *new_array;
asn1_error_code retval;
{ sequence_of(buf);
while (asn1buf_remains(&seqbuf,seqofindef) > 0) {
size++;
new_array = realloc(array,size*sizeof(krb5_authdatatype));
if (new_array == NULL) clean_return(ENOMEM);
array = new_array;
retval = asn1_peek_authdata_elt(&seqbuf,&array[size-1]);
if (retval) clean_return(retval);
}
end_sequence_of(buf);
}
*num = size;
*val = array;
return 0;
error_out:
free(array);
return retval;
}
asn1_error_code
asn1_decode_authdata_elt_ptr(asn1buf *buf, krb5_authdata **valptr)
{
decode_ptr(krb5_authdata *, asn1_decode_authdata_elt);
}
asn1_error_code
asn1_decode_host_addresses(asn1buf *buf, krb5_address ***val)
{
decode_array_body(krb5_address,asn1_decode_host_address_ptr,
krb5_free_address);
}
asn1_error_code
asn1_decode_sequence_of_ticket(asn1buf *buf, krb5_ticket ***val)
{
decode_array_body(krb5_ticket,asn1_decode_ticket_ptr,krb5_free_ticket);
}
static void
free_cred_info(void *dummy, krb5_cred_info *val)
{
krb5_free_keyblock(NULL, val->session);
krb5_free_principal(NULL, val->client);
krb5_free_principal(NULL, val->server);
krb5_free_addresses(NULL, val->caddrs);
free(val);
}
asn1_error_code
asn1_decode_sequence_of_krb_cred_info(asn1buf *buf, krb5_cred_info ***val)
{
decode_array_body(krb5_cred_info,asn1_decode_krb_cred_info_ptr,
free_cred_info);
}
asn1_error_code
asn1_decode_krb_cred_info(asn1buf *buf, krb5_cred_info *val)
{
setup();
val->session = NULL;
val->client = NULL;
val->server = NULL;
val->caddrs = NULL;
{ begin_structure();
get_field(val->session,0,asn1_decode_encryption_key_ptr);
if (tagnum == 1) {
alloc_principal(val->client);
opt_field(val->client,1,asn1_decode_realm,NULL);
opt_field(val->client,2,asn1_decode_principal_name,NULL); }
opt_field(val->flags,3,asn1_decode_ticket_flags,0);
opt_field(val->times.authtime,4,asn1_decode_kerberos_time,0);
opt_field(val->times.starttime,5,asn1_decode_kerberos_time,0);
opt_field(val->times.endtime,6,asn1_decode_kerberos_time,0);
opt_field(val->times.renew_till,7,asn1_decode_kerberos_time,0);
if (tagnum == 8) {
alloc_principal(val->server);
opt_field(val->server,8,asn1_decode_realm,NULL);
opt_field(val->server,9,asn1_decode_principal_name,NULL); }
opt_field(val->caddrs,10,asn1_decode_host_addresses,NULL);
end_structure();
val->magic = KV5M_CRED_INFO;
}
return 0;
error_out:
krb5_free_keyblock(NULL, val->session);
krb5_free_principal(NULL, val->client);
krb5_free_principal(NULL, val->server);
krb5_free_addresses(NULL, val->caddrs);
val->session = NULL;
val->client = NULL;
val->server = NULL;
val->caddrs = NULL;
return retval;
}
asn1_error_code
asn1_decode_krb_cred_info_ptr(asn1buf *buf, krb5_cred_info **valptr)
{
decode_ptr(krb5_cred_info *, asn1_decode_krb_cred_info);
}
static void
free_pa_data(void *dummy, krb5_pa_data *val)
{
free(val->contents);
free(val);
}
asn1_error_code
asn1_decode_sequence_of_pa_data(asn1buf *buf, krb5_pa_data ***val)
{
decode_array_body(krb5_pa_data,asn1_decode_pa_data_ptr,free_pa_data);
}
asn1_error_code
asn1_decode_pa_data(asn1buf *buf, krb5_pa_data *val)
{
setup();
val->contents = NULL;
{ begin_structure();
get_field(val->pa_type,1,asn1_decode_int32);
get_lenfield(val->length,val->contents,2,asn1_decode_octetstring);
end_structure();
val->magic = KV5M_PA_DATA;
}
return 0;
error_out:
free(val->contents);
val->contents = NULL;
return retval;
}
asn1_error_code
asn1_decode_pa_data_ptr(asn1buf *buf, krb5_pa_data **valptr)
{
decode_ptr(krb5_pa_data *, asn1_decode_pa_data);
}
static void
free_last_req_entry(void *dummy, krb5_last_req_entry *val)
{
free(val);
}
asn1_error_code
asn1_decode_last_req(asn1buf *buf, krb5_last_req_entry ***val)
{
decode_array_body(krb5_last_req_entry,asn1_decode_last_req_entry_ptr,
free_last_req_entry);
}
asn1_error_code
asn1_decode_last_req_entry(asn1buf *buf, krb5_last_req_entry *val)
{
setup();
{ begin_structure();
get_field(val->lr_type,0,asn1_decode_int32);
get_field(val->value,1,asn1_decode_kerberos_time);
end_structure();
val->magic = KV5M_LAST_REQ_ENTRY;
#ifdef KRB5_GENEROUS_LR_TYPE
/* If we are only a single byte wide and negative - fill in the
other bits */
if ((val->lr_type & 0xffffff80U) == 0x80) val->lr_type |= 0xffffff00U;
#endif
}
return 0;
error_out:
return retval;
}
asn1_error_code
asn1_decode_last_req_entry_ptr(asn1buf *buf, krb5_last_req_entry **valptr)
{
decode_ptr(krb5_last_req_entry *, asn1_decode_last_req_entry);
}
asn1_error_code
asn1_decode_sequence_of_enctype(asn1buf *buf, int *num, krb5_enctype **val)
{
int size = 0;
krb5_enctype *array = NULL, *new_array;
asn1_error_code retval;
{ sequence_of(buf);
while (asn1buf_remains(&seqbuf,seqofindef) > 0) {
size++;
new_array = realloc(array,size*sizeof(krb5_enctype));
if (new_array == NULL) clean_return(ENOMEM);
array = new_array;
retval = asn1_decode_enctype(&seqbuf,&array[size-1]);
if (retval) clean_return(retval);
}
end_sequence_of(buf);
}
*num = size;
*val = array;
return 0;
error_out:
free(array);
return retval;
}
asn1_error_code
asn1_decode_sequence_of_checksum(asn1buf *buf, krb5_checksum ***val)
{
decode_array_body(krb5_checksum, asn1_decode_checksum_ptr,
krb5_free_checksum);
}
static void
free_etype_info_entry(void *dummy, krb5_etype_info_entry *val)
{
krb5_free_data_contents(NULL, &val->s2kparams);
free(val->salt);
free(val);
}
static asn1_error_code
asn1_decode_etype_info2_entry(asn1buf *buf, krb5_etype_info_entry *val)
{
char *salt = NULL;
krb5_octet *params = NULL;
setup();
val->salt = NULL;
val->s2kparams.data = NULL;
{ begin_structure();
get_field(val->etype,0,asn1_decode_enctype);
if (tagnum == 1) {
get_lenfield(val->length,salt,1,asn1_decode_generalstring);
val->salt = (krb5_octet *) salt;
salt = NULL;
} else
val->length = KRB5_ETYPE_NO_SALT;
if ( tagnum ==2) {
get_lenfield( val->s2kparams.length, params,
2, asn1_decode_octetstring);
val->s2kparams.data = ( char *) params;
params = NULL;
} else
val->s2kparams.length = 0;
end_structure();
val->magic = KV5M_ETYPE_INFO_ENTRY;
}
return 0;
error_out:
free(salt);
free(params);
krb5_free_data_contents(NULL, &val->s2kparams);
free(val->salt);
val->salt = NULL;
return retval;
}
static asn1_error_code
asn1_decode_etype_info2_entry_ptr(asn1buf *buf, krb5_etype_info_entry **valptr)
{
decode_ptr(krb5_etype_info_entry *, asn1_decode_etype_info2_entry);
}
static asn1_error_code
asn1_decode_etype_info2_entry_1_3(asn1buf *buf, krb5_etype_info_entry *val)
{
krb5_octet *params = NULL;
setup();
val->salt = NULL;
val->s2kparams.data = NULL;
{ begin_structure();
get_field(val->etype,0,asn1_decode_enctype);
if (tagnum == 1) {
get_lenfield(val->length,val->salt,1,asn1_decode_octetstring);
} else
val->length = KRB5_ETYPE_NO_SALT;
if ( tagnum ==2) {
get_lenfield( val->s2kparams.length, params,
2, asn1_decode_octetstring);
val->s2kparams.data = ( char *) params;
params = NULL;
} else
val->s2kparams.length = 0;
end_structure();
val->magic = KV5M_ETYPE_INFO_ENTRY;
}
return 0;
error_out:
krb5_free_data_contents(NULL, &val->s2kparams);
free(params);
free(val->salt);
val->salt = NULL;
return retval;
}
static asn1_error_code
asn1_decode_etype_info2_entry_1_3_ptr(asn1buf *buf,
krb5_etype_info_entry **valptr)
{
decode_ptr(krb5_etype_info_entry *, asn1_decode_etype_info2_entry_1_3);
}
static asn1_error_code
asn1_decode_etype_info_entry(asn1buf *buf, krb5_etype_info_entry *val)
{
setup();
val->salt = NULL;
val->s2kparams.data = NULL;
{ begin_structure();
get_field(val->etype,0,asn1_decode_enctype);
if (tagnum == 1) {
get_lenfield(val->length,val->salt,1,asn1_decode_octetstring);
} else
val->length = KRB5_ETYPE_NO_SALT;
val->s2kparams.length = 0;
end_structure();
val->magic = KV5M_ETYPE_INFO_ENTRY;
}
return 0;
error_out:
free(val->salt);
val->salt = NULL;
return retval;
}
static asn1_error_code
asn1_decode_etype_info_entry_ptr(asn1buf *buf, krb5_etype_info_entry **valptr)
{
decode_ptr(krb5_etype_info_entry *, asn1_decode_etype_info_entry);
}
asn1_error_code
asn1_decode_etype_info(asn1buf *buf, krb5_etype_info_entry ***val )
{
decode_array_body(krb5_etype_info_entry,asn1_decode_etype_info_entry_ptr,
free_etype_info_entry);
}
static asn1_error_code
decode_etype_info2_13(asn1buf *buf, krb5_etype_info_entry ***val)
{
decode_array_body(krb5_etype_info_entry,
asn1_decode_etype_info2_entry_1_3_ptr,
free_etype_info_entry);
}
asn1_error_code
asn1_decode_etype_info2(asn1buf *buf, krb5_etype_info_entry ***val ,
krb5_boolean v1_3_behavior)
{
if (v1_3_behavior)
return decode_etype_info2_13(buf, val);
else {
decode_array_body(krb5_etype_info_entry,
asn1_decode_etype_info2_entry_ptr,
free_etype_info_entry);
}
}
asn1_error_code
asn1_decode_passwdsequence(asn1buf *buf, passwd_phrase_element *val)
{
setup();
val->passwd = NULL;
val->phrase = NULL;
{ begin_structure();
alloc_data(val->passwd);
get_lenfield(val->passwd->length,val->passwd->data,
0,asn1_decode_charstring);
val->passwd->magic = KV5M_DATA;
alloc_data(val->phrase);
get_lenfield(val->phrase->length,val->phrase->data,
1,asn1_decode_charstring);
val->phrase->magic = KV5M_DATA;
end_structure();
val->magic = KV5M_PASSWD_PHRASE_ELEMENT;
}
return 0;
error_out:
krb5_free_data(NULL, val->passwd);
krb5_free_data(NULL, val->phrase);
val->passwd = NULL;
val->phrase = NULL;
return 0;
}
asn1_error_code
asn1_decode_passwdsequence_ptr(asn1buf *buf, passwd_phrase_element **valptr)
{
decode_ptr(passwd_phrase_element *, asn1_decode_passwdsequence);
}
asn1_error_code
asn1_decode_sequence_of_passwdsequence(asn1buf *buf,
passwd_phrase_element ***val)
{
decode_array_body(passwd_phrase_element,asn1_decode_passwdsequence_ptr,
krb5_free_passwd_phrase_element);
}
asn1_error_code
asn1_decode_sam_flags(asn1buf *buf, krb5_flags *val)
{
return asn1_decode_krb5_flags(buf,val);
}
#define opt_string(val,n,fn) opt_lenfield((val).length,(val).data,n,fn)
#define opt_cksum(var,tagexpect,decoder) \
if (tagnum == (tagexpect)) { \
get_field_body(var,decoder); } \
else var.length = 0
asn1_error_code
asn1_decode_sam_challenge(asn1buf *buf, krb5_sam_challenge *val)
{
setup();
val->sam_type_name.data = NULL;
val->sam_track_id.data = NULL;
val->sam_challenge_label.data = NULL;
val->sam_response_prompt.data = NULL;
val->sam_pk_for_sad.data = NULL;
val->sam_cksum.contents = NULL;
{ begin_structure();
get_field(val->sam_type,0,asn1_decode_int32);
get_field(val->sam_flags,1,asn1_decode_sam_flags);
opt_string(val->sam_type_name,2,asn1_decode_charstring);
opt_string(val->sam_track_id,3,asn1_decode_charstring);
opt_string(val->sam_challenge_label,4,asn1_decode_charstring);
opt_string(val->sam_challenge,5,asn1_decode_charstring);
opt_string(val->sam_response_prompt,6,asn1_decode_charstring);
opt_string(val->sam_pk_for_sad,7,asn1_decode_charstring);
opt_field(val->sam_nonce,8,asn1_decode_int32,0);
opt_cksum(val->sam_cksum,9,asn1_decode_checksum);
end_structure();
val->magic = KV5M_SAM_CHALLENGE;
}
return 0;
error_out:
krb5_free_sam_challenge_contents(NULL, val);
return retval;
}
asn1_error_code
asn1_decode_sam_challenge_2(asn1buf *buf, krb5_sam_challenge_2 *val)
{
krb5_checksum **cksump;
setup();
val->sam_challenge_2_body.data = NULL;
val->sam_cksum = NULL;
{ char *save, *end;
size_t alloclen;
begin_structure();
if (tagnum != 0) clean_return(ASN1_MISSING_FIELD);
if (asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED)
clean_return(ASN1_BAD_ID);
save = subbuf.next;
{ sequence_of_no_tagvars(&subbuf);
end_sequence_of_no_tagvars(&subbuf);
}
end = subbuf.next;
alloclen = end - save;
val->sam_challenge_2_body.data = malloc(alloclen);
if (!val->sam_challenge_2_body.data)
clean_return(ENOMEM);
val->sam_challenge_2_body.length = alloclen;
memcpy(val->sam_challenge_2_body.data, save, alloclen);
next_tag();
get_field(val->sam_cksum, 1, asn1_decode_sequence_of_checksum);
end_structure();
}
return 0;
error_out:
krb5_free_data_contents(NULL, &val->sam_challenge_2_body);
if (val->sam_cksum) {
for (cksump = val->sam_cksum; *cksump; cksump++)
krb5_free_checksum(NULL, *cksump);
free(val->sam_cksum);
val->sam_cksum = NULL;
}
return retval;
}
asn1_error_code
asn1_decode_sam_challenge_2_body(asn1buf *buf, krb5_sam_challenge_2_body *val)
{
setup();
val->sam_type_name.data = NULL;
val->sam_track_id.data = NULL;
val->sam_challenge_label.data = NULL;
val->sam_challenge.data = NULL;
val->sam_response_prompt.data = NULL;
val->sam_pk_for_sad.data = NULL;
{ begin_structure();
get_field(val->sam_type,0,asn1_decode_int32);
get_field(val->sam_flags,1,asn1_decode_sam_flags);
opt_string(val->sam_type_name,2,asn1_decode_charstring);
opt_string(val->sam_track_id,3,asn1_decode_charstring);
opt_string(val->sam_challenge_label,4,asn1_decode_charstring);
opt_string(val->sam_challenge,5,asn1_decode_charstring);
opt_string(val->sam_response_prompt,6,asn1_decode_charstring);
opt_string(val->sam_pk_for_sad,7,asn1_decode_charstring);
get_field(val->sam_nonce,8,asn1_decode_int32);
get_field(val->sam_etype, 9, asn1_decode_int32);
end_structure();
val->magic = KV5M_SAM_CHALLENGE;
}
return 0;
error_out:
krb5_free_sam_challenge_2_body_contents(NULL, val);
return retval;
}
asn1_error_code
asn1_decode_enc_sam_key(asn1buf *buf, krb5_sam_key *val)
{
setup();
val->sam_key.contents = NULL;
{ begin_structure();
get_field(val->sam_key,0,asn1_decode_encryption_key);
end_structure();
val->magic = KV5M_SAM_KEY;
}
return 0;
error_out:
krb5_free_keyblock_contents(NULL, &val->sam_key);
return retval;
}
asn1_error_code
asn1_decode_enc_sam_response_enc(asn1buf *buf, krb5_enc_sam_response_enc *val)
{
setup();
val->sam_sad.data = NULL;
{ begin_structure();
opt_field(val->sam_nonce,0,asn1_decode_int32,0);
opt_field(val->sam_timestamp,1,asn1_decode_kerberos_time,0);
opt_field(val->sam_usec,2,asn1_decode_int32,0);
opt_string(val->sam_sad,3,asn1_decode_charstring);
end_structure();
val->magic = KV5M_ENC_SAM_RESPONSE_ENC;
}
return 0;
error_out:
krb5_free_enc_sam_response_enc_contents(NULL, val);
return retval;
}
asn1_error_code
asn1_decode_enc_sam_response_enc_2(asn1buf *buf, krb5_enc_sam_response_enc_2 *val)
{
setup();
val->sam_sad.data = NULL;
{ begin_structure();
get_field(val->sam_nonce,0,asn1_decode_int32);
opt_string(val->sam_sad,1,asn1_decode_charstring);
end_structure();
val->magic = KV5M_ENC_SAM_RESPONSE_ENC_2;
}
return 0;
error_out:
krb5_free_enc_sam_response_enc_2_contents(NULL, val);
return retval;
}
#define opt_encfield(fld,tag,fn) \
if (tagnum == tag) { \
get_field(fld,tag,fn); } \
else { \
fld.magic = 0; \
fld.enctype = 0; \
fld.kvno = 0; \
fld.ciphertext.data = NULL; \
fld.ciphertext.length = 0; \
}
asn1_error_code
asn1_decode_sam_response(asn1buf *buf, krb5_sam_response *val)
{
setup();
val->sam_track_id.data = NULL;
val->sam_enc_key.ciphertext.data = NULL;
val->sam_enc_nonce_or_ts.ciphertext.data = NULL;
{ begin_structure();
get_field(val->sam_type,0,asn1_decode_int32);
get_field(val->sam_flags,1,asn1_decode_sam_flags);
opt_string(val->sam_track_id,2,asn1_decode_charstring);
opt_encfield(val->sam_enc_key,3,asn1_decode_encrypted_data);
get_field(val->sam_enc_nonce_or_ts,4,asn1_decode_encrypted_data);
opt_field(val->sam_nonce,5,asn1_decode_int32,0);
opt_field(val->sam_patimestamp,6,asn1_decode_kerberos_time,0);
end_structure();
val->magic = KV5M_SAM_RESPONSE;
}
return 0;
error_out:
krb5_free_sam_response_contents(NULL, val);
return retval;
}
asn1_error_code
asn1_decode_sam_response_2(asn1buf *buf, krb5_sam_response_2 *val)
{
setup();
val->sam_track_id.data = NULL;
val->sam_enc_nonce_or_sad.ciphertext.data = NULL;
{ begin_structure();
get_field(val->sam_type,0,asn1_decode_int32);
get_field(val->sam_flags,1,asn1_decode_sam_flags);
opt_string(val->sam_track_id,2,asn1_decode_charstring);
get_field(val->sam_enc_nonce_or_sad,3,asn1_decode_encrypted_data);
get_field(val->sam_nonce,4,asn1_decode_int32);
end_structure();
val->magic = KV5M_SAM_RESPONSE;
}
return 0;
error_out:
krb5_free_sam_response_2_contents(NULL, val);
return retval;
}
asn1_error_code
asn1_decode_predicted_sam_response(asn1buf *buf,
krb5_predicted_sam_response *val)
{
setup();
val->sam_key.contents = NULL;
val->client = NULL;
val->msd.data = NULL;
{ begin_structure();
get_field(val->sam_key,0,asn1_decode_encryption_key);
get_field(val->sam_flags,1,asn1_decode_sam_flags);
get_field(val->stime,2,asn1_decode_kerberos_time);
get_field(val->susec,3,asn1_decode_int32);
alloc_principal(val->client);
get_field(val->client,4,asn1_decode_realm);
get_field(val->client,5,asn1_decode_principal_name);
opt_string(val->msd,6,asn1_decode_charstring); /* should be octet */
end_structure();
val->magic = KV5M_PREDICTED_SAM_RESPONSE;
}
return 0;
error_out:
krb5_free_predicted_sam_response_contents(NULL, val);
return retval;
}
asn1_error_code
asn1_decode_setpw_req(asn1buf *buf, krb5_data *newpasswd,
krb5_principal *principal)
{
krb5_principal princ = NULL;
setup();
*principal = NULL;
newpasswd->data = NULL;
{ begin_structure();
get_lenfield(newpasswd->length, newpasswd->data, 0, asn1_decode_charstring);
if (tagnum == 1) {
alloc_principal(princ);
opt_field(princ, 1, asn1_decode_principal_name, 0);
opt_field(princ, 2, asn1_decode_realm, 0);
}
end_structure();
}
*principal = princ;
return 0;
error_out:
krb5_free_data_contents(NULL, newpasswd);
krb5_free_principal(NULL, princ);
return retval;
}
asn1_error_code
asn1_decode_pa_for_user(asn1buf *buf, krb5_pa_for_user *val)
{
setup();
val->user = NULL;
val->cksum.contents = NULL;
val->auth_package.data = NULL;
{ begin_structure();
alloc_principal(val->user);
get_field(val->user,0,asn1_decode_principal_name);
get_field(val->user,1,asn1_decode_realm);
get_field(val->cksum,2,asn1_decode_checksum);
get_lenfield(val->auth_package.length,val->auth_package.data,3,asn1_decode_generalstring);
end_structure();
}
return 0;
error_out:
krb5_free_principal(NULL, val->user);
krb5_free_checksum_contents(NULL, &val->cksum);
krb5_free_data_contents(NULL, &val->auth_package);
val->user = NULL;
return retval;
}
asn1_error_code
asn1_decode_s4u_userid(asn1buf *buf, krb5_s4u_userid *val)
{
setup();
val->nonce = 0;
val->user = NULL;
val->subject_cert.data = NULL;
val->options = 0;
{ begin_structure();
get_field(val->nonce,0,asn1_decode_int32);
alloc_principal(val->user);
opt_field(val->user,1,asn1_decode_principal_name,0);
get_field(val->user,2,asn1_decode_realm);
opt_lenfield(val->subject_cert.length,val->subject_cert.data,3,asn1_decode_charstring);
opt_field(val->options,4,asn1_decode_krb5_flags,0);
end_structure();
}
return 0;
error_out:
krb5_free_principal(NULL, val->user);
krb5_free_data_contents(NULL, &val->subject_cert);
val->user = NULL;
val->subject_cert.data = NULL;
return retval;
}
asn1_error_code
asn1_decode_pa_s4u_x509_user(asn1buf *buf, krb5_pa_s4u_x509_user *val)
{
setup();
val->cksum.contents = NULL;
{ begin_structure();
get_field(val->user_id,0,asn1_decode_s4u_userid);
get_field(val->cksum,1,asn1_decode_checksum);
end_structure();
}
return 0;
error_out:
krb5_free_s4u_userid_contents(NULL, &val->user_id);
krb5_free_checksum_contents(NULL, &val->cksum);
return retval;
}
asn1_error_code
asn1_decode_pa_pac_req(asn1buf *buf, krb5_pa_pac_req *val)
{
setup();
{ begin_structure();
get_field(val->include_pac,0,asn1_decode_boolean);
end_structure();
}
return 0;
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)
{
setup();
val->ad_checksum.contents = NULL;
val->i_principal = NULL;
val->elements = NULL;
{begin_structure();
get_field(val->ad_checksum, 0, asn1_decode_checksum);
if (tagnum == 1) {
alloc_principal(val->i_principal);
opt_field(val->i_principal, 1, asn1_decode_realm, 0);
opt_field(val->i_principal, 2, asn1_decode_principal_name, 0);
}
get_field(val->elements, 3, asn1_decode_authorization_data);
end_structure();
}
return 0;
error_out:
krb5_free_checksum_contents(NULL, &val->ad_checksum);
krb5_free_principal(NULL, val->i_principal);
krb5_free_authdata(NULL, val->elements);
return retval;
}
static asn1_error_code asn1_decode_princ_plus_realm
(asn1buf *buf, krb5_principal *valptr)
{
setup();
alloc_principal((*valptr));
{ begin_structure();
get_field((*valptr), 0, asn1_decode_principal_name);
get_field((*valptr), 1, asn1_decode_realm);
end_structure();
}
return 0;
error_out:
krb5_free_principal(NULL, *valptr);
*valptr = NULL;
return retval;
}
static asn1_error_code
asn1_decode_sequence_of_princ_plus_realm(asn1buf *buf, krb5_principal **val)
{
decode_array_body(krb5_principal_data,asn1_decode_princ_plus_realm,krb5_free_principal);
}
asn1_error_code
asn1_decode_ad_signedpath(asn1buf *buf, krb5_ad_signedpath *val)
{
setup();
val->enctype = ENCTYPE_NULL;
val->checksum.contents = NULL;
val->delegated = NULL;
{
begin_structure();
get_field(val->enctype, 0, asn1_decode_enctype);
get_field(val->checksum, 1, asn1_decode_checksum);
opt_field(val->delegated, 2, asn1_decode_sequence_of_princ_plus_realm,
NULL);
opt_field(val->method_data, 3, asn1_decode_sequence_of_pa_data, NULL);
end_structure();
}
return 0;
error_out:
krb5_free_checksum_contents(NULL, &val->checksum);
return retval;
}
#ifndef DISABLE_PKINIT
/* PKINIT */
asn1_error_code
asn1_decode_external_principal_identifier(
asn1buf *buf,
krb5_external_principal_identifier *val)
{
setup();
val->subjectName.data = NULL;
val->issuerAndSerialNumber.data = NULL;
val->subjectKeyIdentifier.data = NULL;
{
begin_structure();
opt_implicit_octet_string(val->subjectName.length, val->subjectName.data, 0);
opt_implicit_octet_string(val->issuerAndSerialNumber.length, val->issuerAndSerialNumber.data, 1);
opt_implicit_octet_string(val->subjectKeyIdentifier.length, val->subjectKeyIdentifier.data, 2);
end_structure();
}
return 0;
error_out:
free(val->subjectName.data);
free(val->issuerAndSerialNumber.data);
free(val->subjectKeyIdentifier.data);
val->subjectName.data = NULL;
val->issuerAndSerialNumber.data = NULL;
val->subjectKeyIdentifier.data = NULL;
return retval;
}
asn1_error_code
asn1_decode_external_principal_identifier_ptr(
asn1buf *buf,
krb5_external_principal_identifier **valptr)
{
decode_ptr(krb5_external_principal_identifier *,
asn1_decode_external_principal_identifier);
}
static void
free_external_principal_identifier(void *dummy,
krb5_external_principal_identifier *val)
{
free(val->subjectName.data);
free(val->issuerAndSerialNumber.data);
free(val->subjectKeyIdentifier.data);
free(val);
}
asn1_error_code
asn1_decode_sequence_of_external_principal_identifier(
asn1buf *buf,
krb5_external_principal_identifier ***val)
{
decode_array_body(krb5_external_principal_identifier,
asn1_decode_external_principal_identifier_ptr,
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)
{
setup();
val->choice = choice_trusted_cas_UNKNOWN;
{
char *start, *end;
size_t alloclen;
begin_explicit_choice();
if (t.tagnum == choice_trusted_cas_principalName) {
val->choice = choice_trusted_cas_principalName;
} else if (t.tagnum == choice_trusted_cas_caName) {
val->choice = choice_trusted_cas_caName;
val->u.caName.data = NULL;
start = subbuf.next;
{
sequence_of_no_tagvars(&subbuf);
unused_var(size);
end_sequence_of_no_tagvars(&subbuf);
}
end = subbuf.next;
alloclen = end - start;
val->u.caName.data = malloc(alloclen);
if (val->u.caName.data == NULL)
clean_return(ENOMEM);
memcpy(val->u.caName.data, start, alloclen);
val->u.caName.length = alloclen;
next_tag();
} else if (t.tagnum == choice_trusted_cas_issuerAndSerial) {
val->choice = choice_trusted_cas_issuerAndSerial;
val->u.issuerAndSerial.data = NULL;
start = subbuf.next;
{
sequence_of_no_tagvars(&subbuf);
unused_var(size);
end_sequence_of_no_tagvars(&subbuf);
}
end = subbuf.next;
alloclen = end - start;
val->u.issuerAndSerial.data = malloc(alloclen);
if (val->u.issuerAndSerial.data == NULL)
clean_return(ENOMEM);
memcpy(val->u.issuerAndSerial.data, start, alloclen);
val->u.issuerAndSerial.length = alloclen;
next_tag();
} else clean_return(ASN1_BAD_ID);
end_explicit_choice();
}
return 0;
error_out:
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);
val->choice = choice_trusted_cas_UNKNOWN;
return retval;
}
#else
asn1_error_code
asn1_decode_trusted_ca(asn1buf *buf, krb5_trusted_ca *val)
{
setup();
val->choice = choice_trusted_cas_UNKNOWN;
{ begin_choice();
if (tagnum == choice_trusted_cas_principalName) {
val->choice = choice_trusted_cas_principalName;
val->u.principalName = NULL;
asn1_decode_krb5_principal_name(&subbuf, &(val->u.principalName));
} else if (tagnum == choice_trusted_cas_caName) {
val->choice = choice_trusted_cas_caName;
val->u.caName.data = NULL;
get_implicit_octet_string(val->u.caName.length, val->u.caName.data, choice_trusted_cas_caName);
} else if (tagnum == choice_trusted_cas_issuerAndSerial) {
val->choice = choice_trusted_cas_issuerAndSerial;
val->u.issuerAndSerial.data = NULL;
get_implicit_octet_string(val->u.issuerAndSerial.length, val->u.issuerAndSerial.data,
choice_trusted_cas_issuerAndSerial);
} else clean_return(ASN1_BAD_ID);
end_choice();
}
return 0;
error_out:
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);
val->choice = choice_trusted_cas_UNKNOWN;
return retval;
}
#endif
asn1_error_code
asn1_decode_trusted_ca_ptr(asn1buf *buf, krb5_trusted_ca **valptr)
{
decode_ptr(krb5_trusted_ca *, asn1_decode_trusted_ca);
}
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_sequence_of_trusted_ca(asn1buf *buf, krb5_trusted_ca ***val)
{
decode_array_body(krb5_trusted_ca, asn1_decode_trusted_ca_ptr,
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)
{
setup();
val->dhSignedData.data = NULL;
val->serverDHNonce.data = NULL;
{ begin_structure();
get_implicit_octet_string(val->dhSignedData.length, val->dhSignedData.data, 0);
opt_lenfield(val->serverDHNonce.length, val->serverDHNonce.data, 1, asn1_decode_octetstring);
end_structure();
}
return 0;
error_out:
free(val->dhSignedData.data);
free(val->serverDHNonce.data);
val->dhSignedData.data = NULL;
val->serverDHNonce.data = NULL;
return retval;
}
asn1_error_code
asn1_decode_pk_authenticator(asn1buf *buf, krb5_pk_authenticator *val)
{
setup();
val->paChecksum.contents = NULL;
{ begin_structure();
get_field(val->cusec, 0, asn1_decode_int32);
get_field(val->ctime, 1, asn1_decode_kerberos_time);
get_field(val->nonce, 2, asn1_decode_int32);
opt_lenfield(val->paChecksum.length, val->paChecksum.contents, 3, asn1_decode_octetstring);
end_structure();
}
return 0;
error_out:
krb5_free_checksum_contents(NULL, &val->paChecksum);
return retval;
}
asn1_error_code
asn1_decode_pk_authenticator_draft9(asn1buf *buf,
krb5_pk_authenticator_draft9 *val)
{
setup();
val->kdcName = NULL;
val->kdcRealm.data = NULL;
{ begin_structure();
alloc_principal(val->kdcName);
get_field(val->kdcName, 0, asn1_decode_principal_name);
get_field(val->kdcName, 1, asn1_decode_realm);
get_field(val->cusec, 2, asn1_decode_int32);
get_field(val->ctime, 3, asn1_decode_kerberos_time);
get_field(val->nonce, 4, asn1_decode_int32);
end_structure();
}
return 0;
error_out:
krb5_free_principal(NULL, val->kdcName);
return retval;
}
asn1_error_code
asn1_decode_algorithm_identifier(asn1buf *buf, krb5_algorithm_identifier *val)
{
setup();
val->algorithm.data = NULL;
val->parameters.data = NULL;
{ begin_structure_no_tag();
/*
* Forbid indefinite encoding because we don't read enough tag
* information from the trailing octets ("ANY DEFINED BY") to
* synchronize EOC tags, etc.
*/
if (seqindef) clean_return(ASN1_BAD_FORMAT);
/*
* Set up tag variables because we don't actually call anything
* that fetches tag info for us; it's all buried in the decoder
* primitives.
*/
tagnum = ASN1_TAGNUM_CEILING;
asn1class = UNIVERSAL;
construction = PRIMITIVE;
taglen = 0;
indef = 0;
retval = asn1_decode_oid(&subbuf, &val->algorithm.length,
&val->algorithm.data);
if (retval) clean_return(retval);
val->parameters.length = 0;
val->parameters.data = NULL;
assert(subbuf.next >= subbuf.base);
if (length > (size_t)(subbuf.next - subbuf.base)) {
unsigned int size = length - (subbuf.next - subbuf.base);
retval = asn1buf_remove_octetstring(&subbuf, size,
&val->parameters.data);
if (retval) clean_return(retval);
val->parameters.length = size;
}
end_structure();
}
return 0;
error_out:
free(val->algorithm.data);
free(val->parameters.data);
val->algorithm.data = NULL;
val->parameters.data = NULL;
return retval;
}
asn1_error_code
asn1_decode_algorithm_identifier_ptr(asn1buf *buf,
krb5_algorithm_identifier **valptr)
{
decode_ptr(krb5_algorithm_identifier *, asn1_decode_algorithm_identifier);
}
asn1_error_code
asn1_decode_subject_pk_info(asn1buf *buf, krb5_subject_pk_info *val)
{
asn1_octet unused;
setup();
val->algorithm.algorithm.data = NULL;
val->algorithm.parameters.data = NULL;
val->subjectPublicKey.data = NULL;
{ begin_structure_no_tag();
retval = asn1_decode_algorithm_identifier(&subbuf, &val->algorithm);
if (retval) clean_return(retval);
/* SubjectPublicKey encoded as a BIT STRING */
next_tag();
if (asn1class != UNIVERSAL || construction != PRIMITIVE ||
tagnum != ASN1_BITSTRING)
clean_return(ASN1_BAD_ID);
retval = asn1buf_remove_octet(&subbuf, &unused);
if (retval) clean_return(retval);
/* Number of unused bits must be between 0 and 7. */
/* What to do if unused is not zero? */
if (unused > 7) clean_return(ASN1_BAD_FORMAT);
taglen--;
val->subjectPublicKey.length = 0;
val->subjectPublicKey.data = NULL;
retval = asn1buf_remove_octetstring(&subbuf, taglen,
&val->subjectPublicKey.data);
if (retval) clean_return(retval);
val->subjectPublicKey.length = taglen;
/*
* We didn't call any macro that does next_tag(); do so now to
* preload tag of any trailing encodings.
*/
next_tag();
end_structure();
}
return 0;
error_out:
free(val->algorithm.algorithm.data);
free(val->algorithm.parameters.data);
free(val->subjectPublicKey.data);
val->algorithm.algorithm.data = NULL;
val->algorithm.parameters.data = NULL;
val->subjectPublicKey.data = NULL;
return 0;
}
static void
free_algorithm_identifier(void *dummy, krb5_algorithm_identifier *val)
{
free(val->algorithm.data);
free(val->parameters.data);
free(val);
}
asn1_error_code
asn1_decode_sequence_of_algorithm_identifier(asn1buf *buf,
krb5_algorithm_identifier ***val)
{
decode_array_body(krb5_algorithm_identifier,
asn1_decode_algorithm_identifier_ptr,
free_algorithm_identifier);
}
asn1_error_code
asn1_decode_kdc_dh_key_info(asn1buf *buf, krb5_kdc_dh_key_info *val)
{
setup();
val->subjectPublicKey.data = NULL;
{ begin_structure();
retval = asn1buf_remove_octetstring(&subbuf, taglen, &val->subjectPublicKey.data);
if (retval) clean_return(retval);
val->subjectPublicKey.length = taglen;
next_tag();
get_field(val->nonce, 1, asn1_decode_int32);
opt_field(val->dhKeyExpiration, 2, asn1_decode_kerberos_time, 0);
end_structure();
}
return 0;
error_out:
free(val->subjectPublicKey.data);
val->subjectPublicKey.data = NULL;
return retval;
}
asn1_error_code
asn1_decode_reply_key_pack (asn1buf *buf, krb5_reply_key_pack *val)
{
setup();
val->replyKey.contents = NULL;
val->asChecksum.contents = NULL;
{ begin_structure();
get_field(val->replyKey, 0, asn1_decode_encryption_key);
get_field(val->asChecksum, 1, asn1_decode_checksum);
end_structure();
}
return 0;
error_out:
free(val->replyKey.contents);
free(val->asChecksum.contents);
val->replyKey.contents = NULL;
val->asChecksum.contents = NULL;
return retval;
}
asn1_error_code
asn1_decode_reply_key_pack_draft9 (asn1buf *buf,
krb5_reply_key_pack_draft9 *val)
{
setup();
val->replyKey.contents = NULL;
{ begin_structure();
get_field(val->replyKey, 0, asn1_decode_encryption_key);
get_field(val->nonce, 1, asn1_decode_int32);
end_structure();
}
return 0;
error_out:
free(val->replyKey.contents);
val->replyKey.contents = NULL;
return retval;
}
asn1_error_code
asn1_decode_krb5_principal_name (asn1buf *buf, krb5_principal *val)
{
int i;
setup();
(*val)->realm.data = NULL;
(*val)->data = NULL;
{ begin_structure();
get_field(*val, 0, asn1_decode_realm);
get_field(*val, 1, asn1_decode_principal_name);
end_structure();
}
return 0;
error_out:
krb5_free_data_contents(NULL, &(*val)->realm);
if ((*val)->data) {
for (i = 0; i < (*val)->length; i++)
krb5_free_data_contents(NULL, &(*val)->data[i]);
free((*val)->data);
}
(*val)->realm.data = NULL;
(*val)->data = NULL;
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)
{
setup();
val->choice = choice_pa_pk_as_rep_UNKNOWN;
{ begin_choice();
if (tagnum == choice_pa_pk_as_rep_dhInfo) {
val->choice = choice_pa_pk_as_rep_dhInfo;
val->u.dh_Info.dhSignedData.data = NULL;
val->u.dh_Info.serverDHNonce.data = NULL;
get_field_body(val->u.dh_Info, asn1_decode_dh_rep_info);
} else if (tagnum == choice_pa_pk_as_rep_encKeyPack) {
val->choice = choice_pa_pk_as_rep_encKeyPack;
val->u.encKeyPack.data = NULL;
get_implicit_octet_string(val->u.encKeyPack.length, val->u.encKeyPack.data,
choice_pa_pk_as_rep_encKeyPack);
} else {
val->choice = choice_pa_pk_as_rep_UNKNOWN;
}
end_choice();
}
return 0;
error_out:
if (val->choice == choice_pa_pk_as_rep_dhInfo) {
free(val->u.dh_Info.dhSignedData.data);
free(val->u.dh_Info.serverDHNonce.data);
} else if (val->choice == choice_pa_pk_as_rep_encKeyPack) {
free(val->u.encKeyPack.data);
}
val->choice = choice_pa_pk_as_rep_UNKNOWN;
return retval;
}
asn1_error_code
asn1_decode_pa_pk_as_rep_draft9(asn1buf *buf, krb5_pa_pk_as_rep_draft9 *val)
{
setup();
val->choice = choice_pa_pk_as_rep_draft9_UNKNOWN;
{ begin_structure();
if (tagnum == choice_pa_pk_as_rep_draft9_dhSignedData) {
val->choice = choice_pa_pk_as_rep_draft9_dhSignedData;
val->u.dhSignedData.data = NULL;
get_lenfield(val->u.dhSignedData.length, val->u.dhSignedData.data,
choice_pa_pk_as_rep_draft9_dhSignedData, asn1_decode_octetstring);
} else if (tagnum == choice_pa_pk_as_rep_draft9_encKeyPack) {
val->choice = choice_pa_pk_as_rep_draft9_encKeyPack;
val->u.encKeyPack.data = NULL;
get_lenfield(val->u.encKeyPack.length, val->u.encKeyPack.data,
choice_pa_pk_as_rep_draft9_encKeyPack, asn1_decode_octetstring);
} else {
val->choice = choice_pa_pk_as_rep_draft9_UNKNOWN;
}
end_structure();
}
return 0;
error_out:
if (val->choice == choice_pa_pk_as_rep_draft9_dhSignedData)
free(val->u.dhSignedData.data);
else if (val->choice == choice_pa_pk_as_rep_draft9_encKeyPack)
free(val->u.encKeyPack.data);
val->choice = choice_pa_pk_as_rep_draft9_UNKNOWN;
return retval;
}
#endif /* DISABLE_PKINIT */
static void free_typed_data(void *dummy, krb5_typed_data *val)
{
free(val->data);
free(val);
}
asn1_error_code
asn1_decode_sequence_of_typed_data(asn1buf *buf, krb5_typed_data ***val)
{
decode_array_body(krb5_typed_data,asn1_decode_typed_data_ptr,
free_typed_data);
}
asn1_error_code
asn1_decode_typed_data(asn1buf *buf, krb5_typed_data *val)
{
setup();
val->data = NULL;
{ begin_structure();
get_field(val->type,0,asn1_decode_int32);
get_lenfield(val->length,val->data,1,asn1_decode_octetstring);
end_structure();
}
return 0;
error_out:
free(val->data);
val->data = NULL;
return retval;
}
asn1_error_code
asn1_decode_typed_data_ptr(asn1buf *buf, krb5_typed_data **valptr)
{
decode_ptr(krb5_typed_data *, asn1_decode_typed_data);
}