blob: 508bc39ff21f0fbd5791df68678c93662124c947 [file] [log] [blame]
Lev Walkinf15320b2004-06-03 03:38:44 +00001/*-
2 * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
3 * Redistribution and modifications are permitted subject to BSD license.
4 */
5#include <constr_TYPE.h>
6#include <ber_tlv_length.h>
7#include <ber_tlv_tag.h>
8
9ssize_t
10ber_fetch_length(int _is_constructed, void *bufptr, size_t size,
11 ber_tlv_len_t *len_r) {
Lev Walkinc2346572004-08-11 09:07:36 +000012 uint8_t *buf = (uint8_t *)bufptr;
Lev Walkinf15320b2004-06-03 03:38:44 +000013 unsigned oct;
14
15 if(size == 0)
16 return 0; /* Want more */
17
18 oct = *(uint8_t *)buf;
19 if((oct & 0x80) == 0) {
20 /*
21 * Short definite length.
22 */
Lev Walkin619b6aa2004-08-19 18:10:27 +000023 *len_r = oct; /* & 0x7F */
Lev Walkinf15320b2004-06-03 03:38:44 +000024 return 1;
25 } else {
26 ber_tlv_len_t len;
Lev Walkind9bd7752004-06-05 08:17:50 +000027 size_t skipped;
Lev Walkinf15320b2004-06-03 03:38:44 +000028
29 if(_is_constructed && oct == 0x80) {
30 *len_r = -1; /* Indefinite length */
31 return 1;
32 }
33
34 if(oct == 0xff) {
35 /* Reserved in standard for future use. */
36 return -1;
37 }
38
39 oct &= 0x7F; /* Leave only the 7 LS bits */
40 for(len = 0, buf++, skipped = 1;
Lev Walkin619b6aa2004-08-19 18:10:27 +000041 oct && (++skipped <= size); buf++, oct--) {
Lev Walkinf15320b2004-06-03 03:38:44 +000042
43 len = (len << 8) | *buf;
44 if(len < 0
45 || (len >> ((8 * sizeof(len)) - 8) && oct > 1)) {
46 /*
47 * Too large length value.
48 */
49 return -1;
50 }
51 }
52
53 if(oct == 0) {
54 *len_r = len;
55 return skipped;
56 }
57
58 return 0; /* Want more */
59 }
60
61}
62
63ssize_t
64ber_skip_length(int _is_constructed, void *ptr, size_t size) {
65 ber_tlv_len_t vlen; /* Length of V in TLV */
66 ssize_t tl; /* Length of L in TLV */
67 ssize_t ll; /* Length of L in TLV */
Lev Walkind9bd7752004-06-05 08:17:50 +000068 size_t skip;
Lev Walkinf15320b2004-06-03 03:38:44 +000069
70 /*
71 * Determine the size of L in TLV.
72 */
73 ll = ber_fetch_length(_is_constructed, ptr, size, &vlen);
74 if(ll <= 0) return ll;
75
76 /*
77 * Definite length.
78 */
79 if(vlen >= 0) {
80 skip = ll + vlen;
81 if(skip > size)
82 return 0; /* Want more */
83 return skip;
84 }
85
86 /*
87 * Indefinite length!
88 */
89 ASN_DEBUG("Skipping indefinite length");
Lev Walkin4ce78ca2004-08-25 01:34:11 +000090 for(skip = ll, ptr = ((char *)ptr) + ll, size -= ll;;) {
Lev Walkinf15320b2004-06-03 03:38:44 +000091 ber_tlv_tag_t tag;
92
93 /* Fetch the tag */
94 tl = ber_fetch_tag(ptr, size, &tag);
95 if(tl <= 0) return tl;
96
97 ll = ber_skip_length(BER_TLV_CONSTRUCTED(ptr),
Lev Walkin4ce78ca2004-08-25 01:34:11 +000098 ((char *)ptr) + tl, size - tl);
Lev Walkinf15320b2004-06-03 03:38:44 +000099 if(ll <= 0) return ll;
100
101 skip += tl + ll;
102
103 /*
104 * This may be the end of the indefinite length structure,
105 * two consecutive 0 octets.
106 * Check if it is true.
107 */
108 if(((uint8_t *)ptr)[0] == 0
109 && ((uint8_t *)ptr)[1] == 0)
110 return skip;
111
Lev Walkin4ce78ca2004-08-25 01:34:11 +0000112 ptr = ((char *)ptr) + tl + ll;
Lev Walkinf15320b2004-06-03 03:38:44 +0000113 size -= tl + ll;
114 }
115
116 /* UNREACHABLE */
117}
118
119ssize_t
120der_tlv_length_serialize(ber_tlv_len_t len, void *bufp, size_t size) {
Lev Walkin619b6aa2004-08-19 18:10:27 +0000121 size_t required_size; /* Size of len encoding */
Lev Walkinc2346572004-08-11 09:07:36 +0000122 uint8_t *buf = (uint8_t *)bufp;
Lev Walkinf15320b2004-06-03 03:38:44 +0000123 uint8_t *end;
Lev Walkin619b6aa2004-08-19 18:10:27 +0000124 size_t i;
Lev Walkinf15320b2004-06-03 03:38:44 +0000125
126 if(len <= 127) {
127 /* Encoded in 1 octet */
128 if(size) *buf = len;
129 return 1;
130 }
131
132 /*
133 * Compute the size of the subsequent bytes.
134 */
Lev Walkin619b6aa2004-08-19 18:10:27 +0000135 for(required_size = 1, i = 8; i < 8 * sizeof(len); i += 8) {
136 if(len >> i)
137 required_size++;
138 else
139 break;
Lev Walkinf15320b2004-06-03 03:38:44 +0000140 }
141
Lev Walkin619b6aa2004-08-19 18:10:27 +0000142 if(size < required_size)
143 return required_size + 1;
144
145 *buf++ = 0x80 | required_size; /* Length of the encoding */
Lev Walkinf15320b2004-06-03 03:38:44 +0000146
147 /*
148 * Produce the len encoding, space permitting.
149 */
Lev Walkin619b6aa2004-08-19 18:10:27 +0000150 end = buf + required_size;
151 for(i -= 8; buf < end; i -= 8, buf++)
152 *buf = (len >> i);
Lev Walkinf15320b2004-06-03 03:38:44 +0000153
Lev Walkin619b6aa2004-08-19 18:10:27 +0000154 return required_size + 1;
Lev Walkinf15320b2004-06-03 03:38:44 +0000155}
156