libisdn
asn1_codec_ber.c
Go to the documentation of this file.
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 }