xref: /illumos-gate/usr/src/lib/gss_mechs/mech_krb5/krb5/asn.1/ldap_key_seq.c (revision 54925bf60766fbb4f1f2d7c843721406a7b7a3fb)
1*54925bf6Swillf #pragma ident	"%Z%%M%	%I%	%E% SMI"
2*54925bf6Swillf 
3*54925bf6Swillf /* ... copyright ... */
4*54925bf6Swillf 
5*54925bf6Swillf /* Novell key-format scheme:
6*54925bf6Swillf 
7*54925bf6Swillf    KrbKeySet ::= SEQUENCE {
8*54925bf6Swillf    attribute-major-vno       [0] UInt16,
9*54925bf6Swillf    attribute-minor-vno       [1] UInt16,
10*54925bf6Swillf    kvno                      [2] UInt32,
11*54925bf6Swillf    mkvno                     [3] UInt32 OPTIONAL,
12*54925bf6Swillf    keys                      [4] SEQUENCE OF KrbKey,
13*54925bf6Swillf    ...
14*54925bf6Swillf    }
15*54925bf6Swillf 
16*54925bf6Swillf    KrbKey ::= SEQUENCE {
17*54925bf6Swillf    salt      [0] KrbSalt OPTIONAL,
18*54925bf6Swillf    key       [1] EncryptionKey,
19*54925bf6Swillf    s2kparams [2] OCTET STRING OPTIONAL,
20*54925bf6Swillf     ...
21*54925bf6Swillf    }
22*54925bf6Swillf 
23*54925bf6Swillf    KrbSalt ::= SEQUENCE {
24*54925bf6Swillf    type      [0] Int32,
25*54925bf6Swillf    salt      [1] OCTET STRING OPTIONAL
26*54925bf6Swillf    }
27*54925bf6Swillf 
28*54925bf6Swillf    EncryptionKey ::= SEQUENCE {
29*54925bf6Swillf    keytype   [0] Int32,
30*54925bf6Swillf    keyvalue  [1] OCTET STRING
31*54925bf6Swillf    }
32*54925bf6Swillf 
33*54925bf6Swillf  */
34*54925bf6Swillf 
35*54925bf6Swillf #include <k5-int.h>
36*54925bf6Swillf #include <kdb.h>
37*54925bf6Swillf 
38*54925bf6Swillf #include "krbasn1.h"
39*54925bf6Swillf #include "asn1_encode.h"
40*54925bf6Swillf #include "asn1_decode.h"
41*54925bf6Swillf #include "asn1_make.h"
42*54925bf6Swillf #include "asn1_get.h"
43*54925bf6Swillf 
44*54925bf6Swillf #define asn1_encode_sequence_of_keys krb5int_ldap_encode_sequence_of_keys
45*54925bf6Swillf #define asn1_decode_sequence_of_keys krb5int_ldap_decode_sequence_of_keys
46*54925bf6Swillf 
47*54925bf6Swillf #define cleanup(err)							\
48*54925bf6Swillf 	{								\
49*54925bf6Swillf 		ret = err;						\
50*54925bf6Swillf 		goto last;						\
51*54925bf6Swillf 	}
52*54925bf6Swillf 
53*54925bf6Swillf #define checkerr							\
54*54925bf6Swillf 		if (ret != 0)						\
55*54925bf6Swillf 			goto last
56*54925bf6Swillf 
57*54925bf6Swillf /************************************************************************/
58*54925bf6Swillf /* Encode the Principal's keys						*/
59*54925bf6Swillf /************************************************************************/
60*54925bf6Swillf 
61*54925bf6Swillf static asn1_error_code
62*54925bf6Swillf asn1_encode_key(asn1buf *buf,
63*54925bf6Swillf 		krb5_key_data key_data,
64*54925bf6Swillf 		unsigned int *retlen)
65*54925bf6Swillf {
66*54925bf6Swillf     asn1_error_code ret = 0;
67*54925bf6Swillf     unsigned int length, sum = 0;
68*54925bf6Swillf 
69*54925bf6Swillf     /* Encode the key type and value.  */
70*54925bf6Swillf     {
71*54925bf6Swillf 	unsigned int key_len = 0;
72*54925bf6Swillf 	/* key value */
73*54925bf6Swillf 	ret = asn1_encode_octetstring (buf,
74*54925bf6Swillf 				       key_data.key_data_length[0],
75*54925bf6Swillf 				       key_data.key_data_contents[0],
76*54925bf6Swillf 				       &length); checkerr;
77*54925bf6Swillf 	key_len += length;
78*54925bf6Swillf 	ret = asn1_make_etag(buf, CONTEXT_SPECIFIC, 1, length, &length); checkerr;
79*54925bf6Swillf 	key_len += length;
80*54925bf6Swillf 	/* key type */
81*54925bf6Swillf 	ret = asn1_encode_integer (buf, key_data.key_data_type[0], &length);
82*54925bf6Swillf 	checkerr;
83*54925bf6Swillf 	key_len += length;
84*54925bf6Swillf 	ret = asn1_make_etag(buf, CONTEXT_SPECIFIC, 0, length, &length); checkerr;
85*54925bf6Swillf 	key_len += length;
86*54925bf6Swillf 
87*54925bf6Swillf 	ret = asn1_make_sequence(buf, key_len, &length); checkerr;
88*54925bf6Swillf 	key_len += length;
89*54925bf6Swillf 	ret = asn1_make_etag(buf, CONTEXT_SPECIFIC, 1, key_len, &length); checkerr;
90*54925bf6Swillf 	key_len += length;
91*54925bf6Swillf 
92*54925bf6Swillf 	sum += key_len;
93*54925bf6Swillf     }
94*54925bf6Swillf     /* Encode the salt type and value (optional) */
95*54925bf6Swillf     if (key_data.key_data_ver > 1) {
96*54925bf6Swillf 	unsigned int salt_len = 0;
97*54925bf6Swillf 	/* salt value (optional) */
98*54925bf6Swillf 	if (key_data.key_data_length[1] > 0) {
99*54925bf6Swillf 	    ret = asn1_encode_octetstring (buf,
100*54925bf6Swillf 					   key_data.key_data_length[1],
101*54925bf6Swillf 					   key_data.key_data_contents[1],
102*54925bf6Swillf 					   &length); checkerr;
103*54925bf6Swillf 	    salt_len += length;
104*54925bf6Swillf 	    ret = asn1_make_etag(buf, CONTEXT_SPECIFIC, 1, length, &length);
105*54925bf6Swillf 	    checkerr;
106*54925bf6Swillf 	    salt_len += length;
107*54925bf6Swillf 	}
108*54925bf6Swillf 	/* salt type */
109*54925bf6Swillf 	ret = asn1_encode_integer (buf, key_data.key_data_type[1], &length);
110*54925bf6Swillf 	checkerr;
111*54925bf6Swillf 	salt_len += length;
112*54925bf6Swillf 	ret = asn1_make_etag(buf, CONTEXT_SPECIFIC, 0, length, &length); checkerr;
113*54925bf6Swillf 	salt_len += length;
114*54925bf6Swillf 
115*54925bf6Swillf 	ret = asn1_make_sequence(buf, salt_len, &length); checkerr;
116*54925bf6Swillf 	salt_len += length;
117*54925bf6Swillf 	ret = asn1_make_etag(buf, CONTEXT_SPECIFIC, 0, salt_len, &length); checkerr;
118*54925bf6Swillf 	salt_len += length;
119*54925bf6Swillf 
120*54925bf6Swillf 	sum += salt_len;
121*54925bf6Swillf     }
122*54925bf6Swillf 
123*54925bf6Swillf     ret = asn1_make_sequence(buf, sum, &length); checkerr;
124*54925bf6Swillf     sum += length;
125*54925bf6Swillf 
126*54925bf6Swillf     *retlen = sum;
127*54925bf6Swillf 
128*54925bf6Swillf last:
129*54925bf6Swillf     return ret;
130*54925bf6Swillf }
131*54925bf6Swillf 
132*54925bf6Swillf /* Major version and minor version are both '1' - first version */
133*54925bf6Swillf /* asn1_error_code asn1_encode_sequence_of_keys (krb5_key_data *key_data, */
134*54925bf6Swillf krb5_error_code
135*54925bf6Swillf asn1_encode_sequence_of_keys (krb5_key_data *key_data,
136*54925bf6Swillf 			      krb5_int16 n_key_data,
137*54925bf6Swillf 			      krb5_int32 mkvno,	/* Master key version number */
138*54925bf6Swillf 			      krb5_data **code)
139*54925bf6Swillf {
140*54925bf6Swillf     asn1_error_code ret = 0;
141*54925bf6Swillf     asn1buf *buf = NULL;
142*54925bf6Swillf     unsigned int length, sum = 0;
143*54925bf6Swillf     unsigned long tmp_ul;
144*54925bf6Swillf 
145*54925bf6Swillf     *code = NULL;
146*54925bf6Swillf 
147*54925bf6Swillf     if (n_key_data == 0) cleanup (ASN1_MISSING_FIELD);
148*54925bf6Swillf 
149*54925bf6Swillf     /* Allocate the buffer */
150*54925bf6Swillf     ret = asn1buf_create(&buf);
151*54925bf6Swillf     checkerr;
152*54925bf6Swillf 
153*54925bf6Swillf     /* Sequence of keys */
154*54925bf6Swillf     {
155*54925bf6Swillf 	int i;
156*54925bf6Swillf 	unsigned int seq_len = 0;
157*54925bf6Swillf 
158*54925bf6Swillf 	for (i = n_key_data - 1; i >= 0; i--) {
159*54925bf6Swillf 	    ret = asn1_encode_key (buf, key_data[i], &length); checkerr;
160*54925bf6Swillf 	    seq_len += length;
161*54925bf6Swillf 	}
162*54925bf6Swillf 	ret = asn1_make_sequence(buf, seq_len, &length); checkerr;
163*54925bf6Swillf 	seq_len += length;
164*54925bf6Swillf 	ret = asn1_make_etag(buf, CONTEXT_SPECIFIC, 4, seq_len, &length); checkerr;
165*54925bf6Swillf 	seq_len += length;
166*54925bf6Swillf 
167*54925bf6Swillf 	sum += seq_len;
168*54925bf6Swillf     }
169*54925bf6Swillf 
170*54925bf6Swillf     /* mkvno */
171*54925bf6Swillf     if (mkvno < 0)
172*54925bf6Swillf 	cleanup (ASN1_BAD_FORMAT);
173*54925bf6Swillf     tmp_ul = (unsigned long)mkvno;
174*54925bf6Swillf     ret = asn1_encode_unsigned_integer (buf, tmp_ul, &length); checkerr;
175*54925bf6Swillf     sum += length;
176*54925bf6Swillf     ret = asn1_make_etag(buf, CONTEXT_SPECIFIC, 3, length, &length); checkerr;
177*54925bf6Swillf     sum += length;
178*54925bf6Swillf 
179*54925bf6Swillf     /* kvno (assuming all keys in array have same version) */
180*54925bf6Swillf     if (key_data[0].key_data_kvno < 0)
181*54925bf6Swillf 	cleanup (ASN1_BAD_FORMAT);
182*54925bf6Swillf     tmp_ul = (unsigned long)key_data[0].key_data_kvno;
183*54925bf6Swillf     ret = asn1_encode_unsigned_integer (buf, tmp_ul, &length);
184*54925bf6Swillf     checkerr;
185*54925bf6Swillf     sum += length;
186*54925bf6Swillf     ret = asn1_make_etag(buf, CONTEXT_SPECIFIC, 2, length, &length); checkerr;
187*54925bf6Swillf     sum += length;
188*54925bf6Swillf 
189*54925bf6Swillf     /* attribute-minor-vno == 1 */
190*54925bf6Swillf     ret = asn1_encode_unsigned_integer (buf, 1, &length); checkerr;
191*54925bf6Swillf     sum += length;
192*54925bf6Swillf     ret = asn1_make_etag(buf, CONTEXT_SPECIFIC, 1, length, &length); checkerr;
193*54925bf6Swillf     sum += length;
194*54925bf6Swillf 
195*54925bf6Swillf     /* attribute-major-vno == 1 */
196*54925bf6Swillf     ret = asn1_encode_unsigned_integer (buf, 1, &length); checkerr;
197*54925bf6Swillf     sum += length;
198*54925bf6Swillf     ret = asn1_make_etag(buf, CONTEXT_SPECIFIC, 0, length, &length); checkerr;
199*54925bf6Swillf     sum += length;
200*54925bf6Swillf 
201*54925bf6Swillf     ret = asn1_make_sequence(buf, sum, &length); checkerr;
202*54925bf6Swillf     sum += length;
203*54925bf6Swillf 
204*54925bf6Swillf     /* The reverse encoding is straightened out here */
205*54925bf6Swillf     ret = asn12krb5_buf (buf, code); checkerr;
206*54925bf6Swillf 
207*54925bf6Swillf last:
208*54925bf6Swillf     asn1buf_destroy (&buf);
209*54925bf6Swillf 
210*54925bf6Swillf     if (ret != 0 && *code != NULL) {
211*54925bf6Swillf         if ((*code)->data != NULL)
212*54925bf6Swillf             free ((*code)->data);
213*54925bf6Swillf         free (*code);
214*54925bf6Swillf     }
215*54925bf6Swillf 
216*54925bf6Swillf     return ret;
217*54925bf6Swillf }
218*54925bf6Swillf 
219*54925bf6Swillf /************************************************************************/
220*54925bf6Swillf /* Decode the Principal's keys						*/
221*54925bf6Swillf /************************************************************************/
222*54925bf6Swillf 
223*54925bf6Swillf #define safe_syncbuf(outer,inner)					\
224*54925bf6Swillf 	if (! ((inner)->next == (inner)->bound + 1 &&			\
225*54925bf6Swillf 	       (inner)->next == (outer)->next + buflen))		\
226*54925bf6Swillf 	    cleanup (ASN1_BAD_LENGTH);					\
227*54925bf6Swillf 	asn1buf_sync((outer), (inner), 0, 0, 0, 0, 0);
228*54925bf6Swillf 
229*54925bf6Swillf static asn1_error_code
230*54925bf6Swillf decode_tagged_integer (asn1buf *buf, asn1_tagnum expectedtag, long *val)
231*54925bf6Swillf {
232*54925bf6Swillf     int buflen;
233*54925bf6Swillf     asn1_error_code ret = 0;
234*54925bf6Swillf     asn1buf tmp, subbuf;
235*54925bf6Swillf     taginfo t;
236*54925bf6Swillf 
237*54925bf6Swillf     /* Work on a copy of 'buf' */
238*54925bf6Swillf     ret = asn1buf_imbed(&tmp, buf, 0, 1); checkerr;
239*54925bf6Swillf     ret = asn1_get_tag_2(&tmp, &t); checkerr;
240*54925bf6Swillf     if (t.tagnum != expectedtag)
241*54925bf6Swillf 	cleanup (ASN1_MISSING_FIELD);
242*54925bf6Swillf 
243*54925bf6Swillf     buflen = t.length;
244*54925bf6Swillf     ret = asn1buf_imbed(&subbuf, &tmp, t.length, 0); checkerr;
245*54925bf6Swillf     ret = asn1_decode_integer(&subbuf, val); checkerr;
246*54925bf6Swillf 
247*54925bf6Swillf     safe_syncbuf(&tmp, &subbuf);
248*54925bf6Swillf     *buf = tmp;
249*54925bf6Swillf 
250*54925bf6Swillf last:
251*54925bf6Swillf     return ret;
252*54925bf6Swillf }
253*54925bf6Swillf 
254*54925bf6Swillf #if 0 /* not currently used */
255*54925bf6Swillf static asn1_error_code
256*54925bf6Swillf decode_tagged_unsigned_integer (asn1buf *buf, int expectedtag, unsigned long *val)
257*54925bf6Swillf {
258*54925bf6Swillf     int buflen;
259*54925bf6Swillf     asn1_error_code ret = 0;
260*54925bf6Swillf     asn1buf tmp, subbuf;
261*54925bf6Swillf     taginfo t;
262*54925bf6Swillf 
263*54925bf6Swillf     /* Work on a copy of 'buf' */
264*54925bf6Swillf     ret = asn1buf_imbed(&tmp, buf, 0, 1); checkerr;
265*54925bf6Swillf     ret = asn1_get_tag_2(&tmp, &t); checkerr;
266*54925bf6Swillf     if (t.tagnum != expectedtag)
267*54925bf6Swillf 	cleanup (ASN1_MISSING_FIELD);
268*54925bf6Swillf 
269*54925bf6Swillf     buflen = t.length;
270*54925bf6Swillf     ret = asn1buf_imbed(&subbuf, &tmp, t.length, 0); checkerr;
271*54925bf6Swillf     ret = asn1_decode_unsigned_integer(&subbuf, val); checkerr;
272*54925bf6Swillf 
273*54925bf6Swillf     safe_syncbuf(&tmp, &subbuf);
274*54925bf6Swillf     *buf = tmp;
275*54925bf6Swillf 
276*54925bf6Swillf last:
277*54925bf6Swillf     return ret;
278*54925bf6Swillf }
279*54925bf6Swillf #endif
280*54925bf6Swillf 
281*54925bf6Swillf static asn1_error_code
282*54925bf6Swillf decode_tagged_octetstring (asn1buf *buf, asn1_tagnum expectedtag,
283*54925bf6Swillf     unsigned int *len, asn1_octet **val)
284*54925bf6Swillf {
285*54925bf6Swillf     int buflen;
286*54925bf6Swillf     asn1_error_code ret = 0;
287*54925bf6Swillf     asn1buf tmp, subbuf;
288*54925bf6Swillf     taginfo t;
289*54925bf6Swillf 
290*54925bf6Swillf     *val = NULL;
291*54925bf6Swillf 
292*54925bf6Swillf     /* Work on a copy of 'buf' */
293*54925bf6Swillf     ret = asn1buf_imbed(&tmp, buf, 0, 1); checkerr;
294*54925bf6Swillf     ret = asn1_get_tag_2(&tmp, &t); checkerr;
295*54925bf6Swillf     if (t.tagnum != expectedtag)
296*54925bf6Swillf 	cleanup (ASN1_MISSING_FIELD);
297*54925bf6Swillf 
298*54925bf6Swillf     buflen = t.length;
299*54925bf6Swillf     ret = asn1buf_imbed(&subbuf, &tmp, t.length, 0); checkerr;
300*54925bf6Swillf     ret = asn1_decode_octetstring (&subbuf, len, val); checkerr;
301*54925bf6Swillf 
302*54925bf6Swillf     safe_syncbuf(&tmp, &subbuf);
303*54925bf6Swillf     *buf = tmp;
304*54925bf6Swillf 
305*54925bf6Swillf last:
306*54925bf6Swillf     if (ret != 0 && *val != NULL)
307*54925bf6Swillf 	free (*val);
308*54925bf6Swillf     return ret;
309*54925bf6Swillf }
310*54925bf6Swillf 
311*54925bf6Swillf static asn1_error_code asn1_decode_key(asn1buf *buf, krb5_key_data *key)
312*54925bf6Swillf {
313*54925bf6Swillf     int buflen, seqindef;
314*54925bf6Swillf     unsigned int length;
315*54925bf6Swillf     asn1_error_code ret;
316*54925bf6Swillf     asn1buf subbuf;
317*54925bf6Swillf     taginfo t;
318*54925bf6Swillf 
319*54925bf6Swillf     key->key_data_contents[0] = NULL;
320*54925bf6Swillf     key->key_data_contents[1] = NULL;
321*54925bf6Swillf 
322*54925bf6Swillf     ret = asn1_get_sequence(buf, &length, &seqindef); checkerr;
323*54925bf6Swillf     buflen = length;
324*54925bf6Swillf     ret = asn1buf_imbed(&subbuf, buf, length, seqindef); checkerr;
325*54925bf6Swillf 
326*54925bf6Swillf     asn1_get_tag_2(&subbuf, &t);
327*54925bf6Swillf     /* Salt */
328*54925bf6Swillf     if (t.tagnum == 0) {
329*54925bf6Swillf 	int buflen;
330*54925bf6Swillf 	asn1buf slt;
331*54925bf6Swillf 	unsigned long keytype;
332*54925bf6Swillf 	unsigned int keylen;
333*54925bf6Swillf 
334*54925bf6Swillf 	key->key_data_ver = 2;
335*54925bf6Swillf 	asn1_get_sequence(&subbuf, &length, &seqindef);
336*54925bf6Swillf 	buflen = length;
337*54925bf6Swillf 	asn1buf_imbed(&slt, &subbuf, length, seqindef);
338*54925bf6Swillf 
339*54925bf6Swillf 	ret = decode_tagged_integer (&slt, 0, (long *) &keytype);
340*54925bf6Swillf 	key->key_data_type[1] = keytype; /* XXX range check?? */
341*54925bf6Swillf 	checkerr;
342*54925bf6Swillf 
343*54925bf6Swillf 	if (asn1buf_remains(&slt, 0) != 0) { /* Salt value is optional */
344*54925bf6Swillf 	    ret = decode_tagged_octetstring (&slt, 1, &keylen,
345*54925bf6Swillf 		    &key->key_data_contents[1]); checkerr;
346*54925bf6Swillf 	}
347*54925bf6Swillf 	safe_syncbuf (&subbuf, &slt);
348*54925bf6Swillf 	key->key_data_length[1] = keylen; /* XXX range check?? */
349*54925bf6Swillf 
350*54925bf6Swillf 	ret = asn1_get_tag_2(&subbuf, &t); checkerr;
351*54925bf6Swillf     } else
352*54925bf6Swillf 	key->key_data_ver = 1;
353*54925bf6Swillf 
354*54925bf6Swillf     /* Key */
355*54925bf6Swillf     {
356*54925bf6Swillf 	int buflen;
357*54925bf6Swillf 	asn1buf kbuf;
358*54925bf6Swillf 	long lval;
359*54925bf6Swillf 	unsigned int ival;
360*54925bf6Swillf 
361*54925bf6Swillf 	if (t.tagnum != 1)
362*54925bf6Swillf 	    cleanup (ASN1_MISSING_FIELD);
363*54925bf6Swillf 
364*54925bf6Swillf 	ret = asn1_get_sequence(&subbuf, &length, &seqindef); checkerr;
365*54925bf6Swillf 	buflen = length;
366*54925bf6Swillf 	ret = asn1buf_imbed(&kbuf, &subbuf, length, seqindef); checkerr;
367*54925bf6Swillf 
368*54925bf6Swillf 	ret = decode_tagged_integer (&kbuf, 0, &lval);
369*54925bf6Swillf 	checkerr;
370*54925bf6Swillf 	key->key_data_type[0] = lval; /* XXX range check? */
371*54925bf6Swillf 
372*54925bf6Swillf 	ret = decode_tagged_octetstring (&kbuf, 1, &ival,
373*54925bf6Swillf 					 &key->key_data_contents[0]); checkerr;
374*54925bf6Swillf 	key->key_data_length[0] = ival;	/* XXX range check? */
375*54925bf6Swillf 
376*54925bf6Swillf 	safe_syncbuf (&subbuf, &kbuf);
377*54925bf6Swillf     }
378*54925bf6Swillf 
379*54925bf6Swillf     safe_syncbuf (buf, &subbuf);
380*54925bf6Swillf 
381*54925bf6Swillf last:
382*54925bf6Swillf     if (ret != 0) {
383*54925bf6Swillf 	if (key->key_data_contents[0] != NULL) {
384*54925bf6Swillf 	    free (key->key_data_contents[0]);
385*54925bf6Swillf 	    key->key_data_contents[0] = NULL;
386*54925bf6Swillf 	}
387*54925bf6Swillf 	if (key->key_data_contents[1] != NULL) {
388*54925bf6Swillf 	    free (key->key_data_contents[1]);
389*54925bf6Swillf 	    key->key_data_contents[1] = NULL;
390*54925bf6Swillf 	}
391*54925bf6Swillf     }
392*54925bf6Swillf     return ret;
393*54925bf6Swillf }
394*54925bf6Swillf 
395*54925bf6Swillf /* asn1_error_code asn1_decode_sequence_of_keys (krb5_data *in, */
396*54925bf6Swillf krb5_error_code asn1_decode_sequence_of_keys (krb5_data *in,
397*54925bf6Swillf 					      krb5_key_data **out,
398*54925bf6Swillf 					      krb5_int16 *n_key_data,
399*54925bf6Swillf 					      int *mkvno)
400*54925bf6Swillf {
401*54925bf6Swillf     asn1_error_code ret;
402*54925bf6Swillf     asn1buf buf, subbuf;
403*54925bf6Swillf     int seqindef;
404*54925bf6Swillf     unsigned int length;
405*54925bf6Swillf     taginfo t;
406*54925bf6Swillf     int kvno, maj, min;
407*54925bf6Swillf     long lval;
408*54925bf6Swillf 
409*54925bf6Swillf     *n_key_data = 0;
410*54925bf6Swillf     *out = NULL;
411*54925bf6Swillf 
412*54925bf6Swillf     ret = asn1buf_wrap_data(&buf, in); checkerr;
413*54925bf6Swillf 
414*54925bf6Swillf     ret = asn1_get_sequence(&buf, &length, &seqindef); checkerr;
415*54925bf6Swillf     ret = asn1buf_imbed(&subbuf, &buf, length, seqindef); checkerr;
416*54925bf6Swillf 
417*54925bf6Swillf     /* attribute-major-vno */
418*54925bf6Swillf     ret = decode_tagged_integer (&subbuf, 0, &lval); checkerr;
419*54925bf6Swillf     maj = lval;			/* XXX range check? */
420*54925bf6Swillf 
421*54925bf6Swillf     /* attribute-minor-vno */
422*54925bf6Swillf     ret = decode_tagged_integer (&subbuf, 1, &lval); checkerr;
423*54925bf6Swillf     min = lval;			/* XXX range check? */
424*54925bf6Swillf 
425*54925bf6Swillf     if (maj != 1 || min != 1)
426*54925bf6Swillf 	cleanup (ASN1_BAD_FORMAT);
427*54925bf6Swillf 
428*54925bf6Swillf     /* kvno (assuming all keys in array have same version) */
429*54925bf6Swillf     ret = decode_tagged_integer (&subbuf, 2, &lval); checkerr;
430*54925bf6Swillf     kvno = lval;		/* XXX range check? */
431*54925bf6Swillf 
432*54925bf6Swillf     /* mkvno (optional) */
433*54925bf6Swillf     ret = decode_tagged_integer (&subbuf, 3, &lval); checkerr;
434*54925bf6Swillf     *mkvno = lval;		/* XXX range check? */
435*54925bf6Swillf 
436*54925bf6Swillf     ret = asn1_get_tag_2(&subbuf, &t); checkerr;
437*54925bf6Swillf 
438*54925bf6Swillf     /* Sequence of keys */
439*54925bf6Swillf     {
440*54925bf6Swillf 	int i, buflen;
441*54925bf6Swillf 	asn1buf keyseq;
442*54925bf6Swillf 	if (t.tagnum != 4)
443*54925bf6Swillf 	    cleanup (ASN1_MISSING_FIELD);
444*54925bf6Swillf 	ret = asn1_get_sequence(&subbuf, &length, &seqindef); checkerr;
445*54925bf6Swillf 	buflen = length;
446*54925bf6Swillf 	ret = asn1buf_imbed(&keyseq, &subbuf, length, seqindef); checkerr;
447*54925bf6Swillf 	for (i = 1, *out = NULL; ; i++) {
448*54925bf6Swillf 	    krb5_key_data *tmp;
449*54925bf6Swillf 	    tmp = (krb5_key_data *) realloc (*out, i * sizeof (krb5_key_data));
450*54925bf6Swillf 	    if (tmp == NULL)
451*54925bf6Swillf 		cleanup (ENOMEM);
452*54925bf6Swillf 	    *out = tmp;
453*54925bf6Swillf 	    (*out)[i - 1].key_data_kvno = kvno;
454*54925bf6Swillf 	    ret = asn1_decode_key(&keyseq, &(*out)[i - 1]); checkerr;
455*54925bf6Swillf 	    (*n_key_data)++;
456*54925bf6Swillf 	    if (asn1buf_remains(&keyseq, 0) == 0)
457*54925bf6Swillf 		break; /* Not freeing the last key structure */
458*54925bf6Swillf 	}
459*54925bf6Swillf 	safe_syncbuf (&subbuf, &keyseq);
460*54925bf6Swillf     }
461*54925bf6Swillf 
462*54925bf6Swillf     /*
463*54925bf6Swillf      * There could be other data inside the outermost sequence ... tags we don't
464*54925bf6Swillf      * know about. So, not invoking "safe_syncbuf(&buf,&subbuf)"
465*54925bf6Swillf      */
466*54925bf6Swillf 
467*54925bf6Swillf last:
468*54925bf6Swillf     if (ret != 0) {
469*54925bf6Swillf 	int i;
470*54925bf6Swillf 	for (i = 0; i < *n_key_data; i++) {
471*54925bf6Swillf 	    if ((*out)[i].key_data_contents[0] != NULL)
472*54925bf6Swillf 		free ((*out)[i].key_data_contents[0]);
473*54925bf6Swillf 	    if ((*out)[i].key_data_contents[1] != NULL)
474*54925bf6Swillf 		free ((*out)[i].key_data_contents[1]);
475*54925bf6Swillf 	}
476*54925bf6Swillf 	free (*out);
477*54925bf6Swillf 	*out = NULL;
478*54925bf6Swillf     }
479*54925bf6Swillf 
480*54925bf6Swillf     return ret;
481*54925bf6Swillf }
482