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