libisdn
|
00001 /* 00002 * 00003 * 00004 */ 00005 #ifdef HAVE_CONFIG_H 00006 #include "config.h" 00007 #endif 00008 00009 #include <stdio.h> 00010 #include <stdlib.h> 00011 #include <string.h> 00012 00013 #include "asn1.h" 00014 #include "asn1_common.h" 00015 #include "asn1_log.h" 00016 #include "asn1_types.h" 00017 //#include "asn1_list.h" 00018 00019 00020 /************************************************************************************************* 00021 * Codec functions 00022 *************************************************************************************************/ 00023 00024 static int ber_decode_integer(struct asn1_buffer *buf, const int size) 00025 { 00026 int x; 00027 int value = 0; 00028 00029 if (!size) { 00030 return value; 00031 } 00032 00033 /* 00034 * Sign extension (negative value) 00035 */ 00036 if (buf->data[buf->offset] & 0x80) { 00037 value = -1; 00038 } 00039 00040 for (x = 0; x < size; x++) { 00041 value <<= 8; 00042 value |= (buf->data[buf->offset + x] & 0xff); 00043 } 00044 return value; 00045 } 00046 00047 #define INT_MSB1 0x80000000u 00048 #define INT_MSB_MASK8 0xff000000u 00049 00050 static int ber_encode_integer(struct asn1_buffer *buf, const int value) 00051 { 00052 unsigned int mask = INT_MSB_MASK8; 00053 int skip_count = 0; 00054 int offset = buf->offset; 00055 int temp = value; 00056 00057 if (value == 0) { 00058 /* no payload, size = 0 */ 00059 return 0; 00060 } 00061 00062 /* 00063 * Encode value != 0 00064 */ 00065 if (value > 0) { 00066 /* count number of 0x00 bytes */ 00067 while (!(mask & temp)) { 00068 mask >>= 8; 00069 skip_count++; 00070 } 00071 00072 /* check if leading bit is '1', if yes insert 0x00 octet */ 00073 if (temp & INT_MSB1) 00074 buf->data[offset++] = 0; 00075 00076 } else { 00077 /* count number of 0xff bytes */ 00078 while ((mask & temp) == mask) { 00079 mask >>= 8; 00080 skip_count++; 00081 } 00082 } 00083 00084 /* encode remaining octets */ 00085 switch (sizeof(value) - skip_count) { 00086 case 4: 00087 buf->data[offset++] = (temp & 0xff000000) >> 24; 00088 case 3: 00089 buf->data[offset++] = (temp & 0xff0000) >> 16; 00090 case 2: 00091 buf->data[offset++] = (temp & 0xff00) >> 8; 00092 case 1: 00093 buf->data[offset++] = (temp & 0xff); 00094 } 00095 00096 offset -= buf->offset; 00097 buf->offset += offset; 00098 00099 return offset; 00100 } 00101 00102 /* known broken */ 00103 static float ber_decode_real(struct asn1_buffer *buf, const int size) 00104 { 00105 int offset = buf->offset; 00106 float value = 0.0f; 00107 00108 /* X.609 - 8.5.2 */ 00109 if (!size) { 00110 return value; 00111 } 00112 00113 /* 00114 * Encoding types (X.609 - 8.5.5) 00115 */ 00116 if (buf->data[offset] & 0x80) { 00117 /* binary encoding */ 00118 int sign = (buf->data[offset] & 0x40) ? -1 : 1; /* 8.5.6.1 */ 00119 // int base = (buf->data[offset] & 0x30) >> 4; /* 8.5.6.2 */ 00120 int shift = (buf->data[offset] & 0x0c) >> 2; /* 8.5.6.3 */ 00121 int exp = (buf->data[offset] & 0x03); /* 8.5.6.4 */ 00122 int explen = 0; 00123 int tmp = 0; 00124 int x; 00125 00126 offset++; 00127 00128 switch (exp) { 00129 case 3: 00130 explen = buf->data[offset++]; 00131 break; 00132 default: 00133 explen = exp + 1; 00134 } 00135 00136 /* exponent */ 00137 for (exp = 0, x = 0; x < explen; x++) { 00138 exp <<= 8; 00139 exp |= (buf->data[offset++] & 0xff); 00140 } 00141 00142 /* value */ 00143 for (tmp = 0, x = 0; x < size - (explen + 1); x++) { 00144 tmp <<= 8; 00145 tmp |= (buf->data[offset++] & 0xff); 00146 } 00147 00148 /* shift */ 00149 value *= (1 << shift); 00150 00151 /* finally add sign */ 00152 value *= sign; 00153 } 00154 #if 0 00155 else if (buf->data[offset] & 0x40) { 00156 /* SpecialRealValue */ 00157 switch (buf->data[offset + 1]) 00158 case 0x40: 00159 /* +INFINITY */ 00160 value = HUGE_VALF; 00161 break; 00162 case 0x41: 00163 /* -INFINITY */ 00164 value = -HUGE_VALF; 00165 break; 00166 default: 00167 /* error */ 00168 break; 00169 } 00170 } 00171 #endif 00172 else { 00173 /* decimal encoding */ 00174 00175 00176 } 00177 00178 return value; 00179 } 00180 00181 static int ber_encode_real(struct asn1_buffer *buf, const float value) 00182 { 00183 return 0; 00184 } 00185 00186 static int ber_decode_oid(struct asn1_buffer *buf, int *oid, const int size) 00187 { 00188 int offset = buf->offset; 00189 int x, len = 0; 00190 00191 for (x = 0; x < size && len < ASN1_MAXOID; x++) { 00192 unsigned int tmp = 0; 00193 00194 while ((buf->data[offset + x] & 0x80) && x < size) { 00195 tmp |= buf->data[offset + x++] & 0x7f; 00196 tmp <<= 7; 00197 } 00198 if (x == size) { 00199 asn1_error("OID decoding error, packed element exceeds size\n"); 00200 break; 00201 } 00202 tmp |= buf->data[offset + x]; 00203 00204 if (x == 0) { 00205 oid[0] = tmp / 40; 00206 oid[1] = tmp % 40; 00207 len += 2; 00208 } 00209 else { 00210 oid[len++] = tmp; 00211 } 00212 } 00213 if (len == ASN1_MAXOID && x < size) { 00214 asn1_error("OID decoding error, exceeds size\n"); 00215 } 00216 return len; 00217 } 00218 00219 static int ber_encode_oid(struct asn1_buffer *buf, const int *oid, const int size) 00220 { 00221 int offset = buf->offset; 00222 int i; 00223 00224 if (size < 2) { 00225 asn1_error("OID encoding error, too short: %d (min required length: 2)\n", size); 00226 return 0; 00227 } 00228 00229 /* encode first two values */ 00230 buf->data[offset++] = (oid[0] * 40) + oid[1]; 00231 00232 /* encode the rest */ 00233 for (i = 2; i < size; i++) { 00234 /* OID value is small enough, encode directly */ 00235 if (oid[i] <= 0x7f) { 00236 buf->data[offset++] = oid[i] & 0x7f; 00237 } else { 00238 int count = 0; 00239 00240 /* calculate number of iterations (and octets) */ 00241 for (int tmp = oid[i]; tmp; tmp >>= 7) 00242 count++; 00243 00244 /* offset of octet after encoded OID value */ 00245 offset += count; 00246 00247 /* encode octets */ 00248 for (int tmp = oid[i], x = 0; x < count; x++) { 00249 buf->data[(offset - x) - 1] = ((x) ? 0x80 : 0x00) | (tmp & 0x7f); 00250 tmp >>= 7; 00251 } 00252 } 00253 } 00254 00255 /* update buf offset and get relative offset */ 00256 offset -= buf->offset; 00257 buf->offset += offset; 00258 00259 return offset; 00260 } 00261 00265 static int ber_decode_custom(struct asn1_buffer *buf, char *val, const int size) 00266 { 00267 int offset = buf->offset; 00268 00269 memcpy(val, &buf->data[offset], size); 00270 return size; 00271 } 00272 00276 static int ber_encode_custom(struct asn1_buffer *buf, const char *val, const int size) 00277 { 00278 int offset = buf->offset; 00279 00280 memcpy(&buf->data[offset], val, size); 00281 return size; 00282 } 00283 00284 00285 /************************************************************************************************* 00286 * Codec API functions 00287 *************************************************************************************************/ 00288 00289 int ber_decode_header(struct asn1_buffer *buf, struct asn1_header *hdr) 00290 { 00291 int offset = buf->offset; 00292 00293 hdr->asn_class = (buf->data[offset] & 0xc0) >> 6; 00294 hdr->asn_complex = !!(buf->data[offset] & 0x20); 00295 hdr->asn_type = (buf->data[offset] & 0x1f); 00296 offset++; 00297 00298 /* multi-octet tag? */ 00299 if (hdr->asn_type == 0x1f) { 00300 hdr->asn_type = 0; 00301 00302 do { 00303 hdr->asn_type <<= 7; 00304 hdr->asn_type |= buf->data[offset] & 0x7f; 00305 } while (buf->data[offset++] & 0x80 && offset < buf->size); 00306 00307 if (offset == buf->size) { 00308 /* multi-octet tag exceeds buffer size */ 00309 return -1; 00310 } 00311 } 00312 00313 /* decode length */ 00314 if (buf->data[offset] & 0x80) { 00315 int tmp, x; 00316 00317 /* size larger than 127 bytes or indefinite form */ 00318 tmp = buf->data[offset++] & 0x7f; 00319 hdr->size = 0; 00320 00321 if (tmp == 0) { 00322 /* indefinite form */ 00323 goto out; 00324 } 00325 00326 if (tmp > sizeof(int)) { 00327 /* length is too large */ 00328 return -1; 00329 } 00330 00331 /* long form */ 00332 for (x = 0; x < tmp; x++) { 00333 hdr->size <<= 8; 00334 hdr->size |= buf->data[offset + x]; 00335 } 00336 offset += x; 00337 } else { 00338 /* short form */ 00339 hdr->size = buf->data[offset] & 0x7f; 00340 offset++; 00341 } 00342 00343 out: 00344 /* update buf offset and get relative offset */ 00345 offset -= buf->offset; 00346 buf->offset += offset; 00347 00348 return offset; 00349 } 00350 00351 00352 int ber_encode_header(struct asn1_buffer *buf, const struct asn1_header *hdr) 00353 { 00354 int offset = buf->offset; 00355 int tag = hdr->asn_type; 00356 00357 buf->data[offset] = (hdr->asn_class << 6) & 0xc0; 00358 00359 if (hdr->asn_complex) 00360 buf->data[offset] |= 0x20; 00361 00362 /* multi-octet tag? */ 00363 if (tag >= 0x1f) { 00364 int cnt; 00365 00366 buf->data[offset++] |= 0x1f; 00367 00368 /* find first set bit */ 00369 for (cnt = sizeof(int) << 3; cnt > 0; cnt--) { 00370 if (tag & (1 << (cnt - 1))) { 00371 cnt -= 7; /* 7 bits wide mask, subtract the mask size */ 00372 break; 00373 } 00374 } 00375 if (cnt <= 7) { 00376 /* 00377 * only 6 (or less) bits to encode? 00378 * just use the 0x7f mask without shifting then 00379 */ 00380 cnt = 0; 00381 } 00382 00383 do { 00384 /* 00385 * shift bits to encode right, so they are within 0x7f 00386 */ 00387 buf->data[offset] = (cnt > 7) ? ((tag >> cnt) & 0x7f) : (tag & 0x7f); 00388 cnt -= 7; 00389 00390 if (cnt > 0) 00391 buf->data[offset] |= 0x80; 00392 00393 offset++; 00394 } while (cnt > 0 && offset < buf->size); 00395 } else { 00396 buf->data[offset++] |= tag & 0x1f; 00397 } 00398 00399 /* encode length */ 00400 if (hdr->size > 0x7f) { 00401 int x, tmp = hdr->size; 00402 00403 /* long form */ 00404 for (x = 1; tmp; tmp <<= 8) { 00405 if (tmp & 0xff000000) { 00406 buf->data[offset + x] = (tmp & 0xff000000) >> 24; 00407 x++; 00408 } 00409 } 00410 buf->data[offset] = 0x80 | x; 00411 offset += x; 00412 } else if (hdr->size == 0) { 00413 /* indefinite form */ 00414 buf->data[offset++] = 0x80; 00415 } else { 00416 /* short form */ 00417 buf->data[offset++] = hdr->size & 0x7f; 00418 } 00419 00420 /* update buf offset and get relative offset */ 00421 offset -= buf->offset; 00422 buf->offset += offset; 00423 00424 return offset; 00425 } 00426 00427 00428 int ber_header_size(const struct asn1_header *hdr) 00429 { 00430 int offset = 1; 00431 int tag = hdr->asn_type; 00432 00433 /* multi-octet tag? */ 00434 if (tag >= 0x1f) { 00435 int cnt; 00436 00437 /* find first set bit */ 00438 for (cnt = sizeof(int) << 3; cnt; cnt--) { 00439 if (tag & (1 << cnt)) { 00440 cnt -= 7; /* 7 bits wide mask, subtract the mask size */ 00441 break; 00442 } 00443 } 00444 if (cnt <= 7) { 00445 /* 00446 * only 6 (or less) bits to encode? 00447 * just use the 0x7f mask without shifting then 00448 */ 00449 cnt = 0; 00450 } 00451 00452 do { 00453 cnt -= 7; 00454 offset++; 00455 } while (cnt > 0); 00456 } 00457 00458 /* encode length */ 00459 if (hdr->size > 0x7f) { 00460 int x, tmp = hdr->size; 00461 00462 /* long form */ 00463 for (x = 1; tmp; tmp <<= 8) { 00464 if (tmp & 0xff000000) x++; 00465 } 00466 offset += x; 00467 } else { 00468 /* short/indefinite form */ 00469 offset++; 00470 } 00471 00472 asn1_debug("BER Header size: %d\n", offset); 00473 return offset; 00474 } 00475 00476 00477 int ber_decode_value(struct asn1_buffer *buf, struct asn1_object *elem) 00478 { 00479 int offset = buf->offset; 00480 int size = elem->hdr.size; 00481 00482 __asn1_ptr_check(elem); 00483 00484 if (elem->hdr.asn_class == ASN1_CLASS_UNIVERSAL) { 00485 switch (elem->hdr.asn_type) { 00486 case ASN1_TYPE_INTEGER: 00487 { 00488 struct asn1_integer *ptr = (struct asn1_integer *)elem; 00489 00490 ptr->value = ber_decode_integer(buf, size); 00491 offset += size; 00492 } 00493 break; 00494 case ASN1_TYPE_ENUMERATED: 00495 { 00496 struct asn1_enumerated *ptr = (struct asn1_enumerated *)elem; 00497 00498 ptr->value = ber_decode_integer(buf, size); 00499 offset += size; 00500 } 00501 break; 00502 case ASN1_TYPE_REAL: 00503 { 00504 struct asn1_real *ptr = (struct asn1_real *)elem; 00505 00506 ptr->value = ber_decode_real(buf, size); 00507 offset += size; 00508 } 00509 break; 00510 case ASN1_TYPE_OID: 00511 { 00512 struct asn1_oid *ptr = (struct asn1_oid *)elem; 00513 00514 ptr->length = ber_decode_oid(buf, ptr->value, size); 00515 offset += size; 00516 } 00517 break; 00518 00519 default: 00520 if (!elem->hdr.asn_complex) { 00521 struct asn1_string *ptr = (struct asn1_string *)elem; 00522 00523 ptr->length = ber_decode_custom(buf, ptr->value, size); 00524 offset += size; 00525 } 00526 break; 00527 } 00528 } 00529 else if (!elem->hdr.asn_complex) { 00530 struct asn1_string *ptr = (struct asn1_string *)elem; 00531 00532 memcpy(ptr->value, &buf->data[offset], elem->hdr.size); 00533 offset += elem->hdr.size; 00534 } 00535 00536 __asn1_ptr_check(elem); 00537 00538 /* update buf offset and get relative offset */ 00539 offset -= buf->offset; 00540 buf->offset += offset; 00541 00542 return offset; 00543 } 00544 00545 00546 int ber_encode_value(struct asn1_buffer *buf, struct asn1_object *elem) 00547 { 00548 int offset = buf->offset; 00549 int size = elem->hdr.size; 00550 00551 __asn1_ptr_check(elem); 00552 00553 if (elem->hdr.asn_class == ASN1_CLASS_UNIVERSAL) { 00554 switch (elem->hdr.asn_type) { 00555 case ASN1_TYPE_INTEGER: 00556 { 00557 struct asn1_integer *ptr = (struct asn1_integer *)elem; 00558 00559 elem->hdr.size = ber_encode_integer(buf, ptr->value); 00560 offset += size; 00561 } 00562 break; 00563 case ASN1_TYPE_ENUMERATED: 00564 { 00565 struct asn1_enumerated *ptr = (struct asn1_enumerated *)elem; 00566 00567 elem->hdr.size = ber_encode_integer(buf, ptr->value); 00568 offset += size; 00569 } 00570 break; 00571 case ASN1_TYPE_REAL: 00572 { 00573 struct asn1_real *ptr = (struct asn1_real *)elem; 00574 00575 elem->hdr.size = ber_encode_real(buf, ptr->value); 00576 offset += elem->hdr.size; 00577 } 00578 break; 00579 case ASN1_TYPE_OID: 00580 { 00581 struct asn1_oid *ptr = (struct asn1_oid *)elem; 00582 00583 ptr->length = ber_encode_oid(buf, ptr->value, ptr->length); 00584 offset += elem->hdr.size; 00585 } 00586 break; 00587 00588 default: 00589 if (!elem->hdr.asn_complex) { 00590 struct asn1_string *ptr = (struct asn1_string *)elem; 00591 00592 elem->hdr.size = ber_encode_custom(buf, ptr->value, ptr->length); 00593 offset += elem->hdr.size; 00594 } 00595 break; 00596 } 00597 } 00598 else if (!elem->hdr.asn_complex) { 00599 struct asn1_string *ptr = (struct asn1_string *)elem; 00600 00601 memcpy(&buf->data[offset], ptr->value, size); 00602 offset += size; 00603 } 00604 00605 /* update buf offset and get relative offset */ 00606 offset -= buf->offset; 00607 buf->offset += offset; 00608 00609 return offset; 00610 }