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