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