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