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 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 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 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 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 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, */ 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