/src/nss/lib/util/dersubr.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
2 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
3 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
4 | | |
5 | | #include "secder.h" |
6 | | #include <limits.h> |
7 | | #include "secerr.h" |
8 | | |
9 | | int |
10 | | DER_LengthLength(PRUint32 len) |
11 | 225k | { |
12 | 225k | if (len > 127) { |
13 | 137 | if (len > 255) { |
14 | 56 | if (len > 65535L) { |
15 | 0 | if (len > 16777215L) { |
16 | 0 | return 5; |
17 | 0 | } else { |
18 | 0 | return 4; |
19 | 0 | } |
20 | 56 | } else { |
21 | 56 | return 3; |
22 | 56 | } |
23 | 81 | } else { |
24 | 81 | return 2; |
25 | 81 | } |
26 | 225k | } else { |
27 | 225k | return 1; |
28 | 225k | } |
29 | 225k | } |
30 | | |
31 | | unsigned char * |
32 | | DER_StoreHeader(unsigned char *buf, unsigned int code, PRUint32 len) |
33 | 100k | { |
34 | 100k | unsigned char b[4]; |
35 | | |
36 | 100k | b[0] = (unsigned char)(len >> 24); |
37 | 100k | b[1] = (unsigned char)(len >> 16); |
38 | 100k | b[2] = (unsigned char)(len >> 8); |
39 | 100k | b[3] = (unsigned char)len; |
40 | 100k | if ((code & DER_TAGNUM_MASK) == DER_SET || (code & DER_TAGNUM_MASK) == DER_SEQUENCE) |
41 | 31.2k | code |= DER_CONSTRUCTED; |
42 | 100k | *buf++ = code; |
43 | 100k | if (len > 127) { |
44 | 137 | if (len > 255) { |
45 | 56 | if (len > 65535) { |
46 | 0 | if (len > 16777215) { |
47 | 0 | *buf++ = 0x84; |
48 | 0 | *buf++ = b[0]; |
49 | 0 | *buf++ = b[1]; |
50 | 0 | *buf++ = b[2]; |
51 | 0 | *buf++ = b[3]; |
52 | 0 | } else { |
53 | 0 | *buf++ = 0x83; |
54 | 0 | *buf++ = b[1]; |
55 | 0 | *buf++ = b[2]; |
56 | 0 | *buf++ = b[3]; |
57 | 0 | } |
58 | 56 | } else { |
59 | 56 | *buf++ = 0x82; |
60 | 56 | *buf++ = b[2]; |
61 | 56 | *buf++ = b[3]; |
62 | 56 | } |
63 | 81 | } else { |
64 | 81 | *buf++ = 0x81; |
65 | 81 | *buf++ = b[3]; |
66 | 81 | } |
67 | 100k | } else { |
68 | 100k | *buf++ = b[3]; |
69 | 100k | } |
70 | 100k | return buf; |
71 | 100k | } |
72 | | |
73 | | /* |
74 | | * XXX This should be rewritten, generalized, to take a long instead |
75 | | * of a PRInt32. |
76 | | */ |
77 | | SECStatus |
78 | | DER_SetInteger(PLArenaPool *arena, SECItem *it, PRInt32 i) |
79 | 0 | { |
80 | 0 | unsigned char bb[4]; |
81 | 0 | unsigned len; |
82 | |
|
83 | 0 | bb[0] = (unsigned char)(i >> 24); |
84 | 0 | bb[1] = (unsigned char)(i >> 16); |
85 | 0 | bb[2] = (unsigned char)(i >> 8); |
86 | 0 | bb[3] = (unsigned char)(i); |
87 | | |
88 | | /* |
89 | | ** Small integers are encoded in a single byte. Larger integers |
90 | | ** require progressively more space. |
91 | | */ |
92 | 0 | if (i < -128) { |
93 | 0 | if (i < -32768L) { |
94 | 0 | if (i < -8388608L) { |
95 | 0 | len = 4; |
96 | 0 | } else { |
97 | 0 | len = 3; |
98 | 0 | } |
99 | 0 | } else { |
100 | 0 | len = 2; |
101 | 0 | } |
102 | 0 | } else if (i > 127) { |
103 | 0 | if (i > 32767L) { |
104 | 0 | if (i > 8388607L) { |
105 | 0 | len = 4; |
106 | 0 | } else { |
107 | 0 | len = 3; |
108 | 0 | } |
109 | 0 | } else { |
110 | 0 | len = 2; |
111 | 0 | } |
112 | 0 | } else { |
113 | 0 | len = 1; |
114 | 0 | } |
115 | 0 | it->data = (unsigned char *)PORT_ArenaAlloc(arena, len); |
116 | 0 | if (!it->data) { |
117 | 0 | return SECFailure; |
118 | 0 | } |
119 | 0 | it->len = len; |
120 | 0 | PORT_Memcpy(it->data, bb + (4 - len), len); |
121 | 0 | return SECSuccess; |
122 | 0 | } |
123 | | |
124 | | /* |
125 | | * XXX This should be rewritten, generalized, to take an unsigned long instead |
126 | | * of a PRUint32. |
127 | | */ |
128 | | SECStatus |
129 | | DER_SetUInteger(PLArenaPool *arena, SECItem *it, PRUint32 ui) |
130 | 79.6k | { |
131 | 79.6k | unsigned char bb[5]; |
132 | 79.6k | int len; |
133 | | |
134 | 79.6k | bb[0] = 0; |
135 | 79.6k | bb[1] = (unsigned char)(ui >> 24); |
136 | 79.6k | bb[2] = (unsigned char)(ui >> 16); |
137 | 79.6k | bb[3] = (unsigned char)(ui >> 8); |
138 | 79.6k | bb[4] = (unsigned char)(ui); |
139 | | |
140 | | /* |
141 | | ** Small integers are encoded in a single byte. Larger integers |
142 | | ** require progressively more space. |
143 | | */ |
144 | 79.6k | if (ui > 0x7f) { |
145 | 0 | if (ui > 0x7fff) { |
146 | 0 | if (ui > 0x7fffffL) { |
147 | 0 | if (ui >= 0x80000000L) { |
148 | 0 | len = 5; |
149 | 0 | } else { |
150 | 0 | len = 4; |
151 | 0 | } |
152 | 0 | } else { |
153 | 0 | len = 3; |
154 | 0 | } |
155 | 0 | } else { |
156 | 0 | len = 2; |
157 | 0 | } |
158 | 79.6k | } else { |
159 | 79.6k | len = 1; |
160 | 79.6k | } |
161 | | |
162 | 79.6k | it->data = (unsigned char *)PORT_ArenaAlloc(arena, len); |
163 | 79.6k | if (it->data == NULL) { |
164 | 0 | return SECFailure; |
165 | 0 | } |
166 | | |
167 | 79.6k | it->len = len; |
168 | 79.6k | PORT_Memcpy(it->data, bb + (sizeof(bb) - len), len); |
169 | | |
170 | 79.6k | return SECSuccess; |
171 | 79.6k | } |
172 | | |
173 | | /* |
174 | | ** Convert a der encoded *signed* integer into a machine integral value. |
175 | | ** If an underflow/overflow occurs, sets error code and returns min/max. |
176 | | */ |
177 | | long |
178 | | DER_GetInteger(const SECItem *it) |
179 | 9.33k | { |
180 | 9.33k | unsigned long ival; |
181 | 9.33k | PRBool negative; |
182 | 9.33k | unsigned int len = it->len; |
183 | 9.33k | unsigned char *cp = it->data; |
184 | 9.33k | size_t lsize = sizeof(ival); |
185 | | |
186 | 9.33k | PORT_Assert(len); |
187 | 9.33k | if (!len) { |
188 | 0 | PORT_SetError(SEC_ERROR_INPUT_LEN); |
189 | 0 | return 0; |
190 | 0 | } |
191 | | |
192 | 9.33k | negative = (PRBool)(*cp & 0x80); |
193 | 9.33k | ival = negative ? ~0 : 0; |
194 | | |
195 | | /* Ignore leading zeros/ones. */ |
196 | 10.2k | while (len && *cp == (unsigned char)ival) { |
197 | 929 | len--; |
198 | 929 | cp++; |
199 | 929 | } |
200 | | |
201 | | /* Check for overflow/underflow. */ |
202 | 9.33k | if (len > lsize || (len == lsize && (*cp & 0x80) != negative)) { |
203 | 3 | PORT_SetError(SEC_ERROR_BAD_DER); |
204 | 3 | return negative ? LONG_MIN : LONG_MAX; |
205 | 3 | } |
206 | | |
207 | 18.1k | while (len--) { |
208 | 8.83k | ival <<= 8; |
209 | 8.83k | ival |= *cp++; |
210 | 8.83k | } |
211 | | |
212 | 9.33k | return ival; |
213 | 9.33k | } |
214 | | |
215 | | /* |
216 | | ** Convert a der encoded *unsigned* integer into a machine integral value. |
217 | | ** If an overflow occurs, sets error code and returns max. |
218 | | */ |
219 | | unsigned long |
220 | | DER_GetUInteger(SECItem *it) |
221 | 0 | { |
222 | 0 | unsigned long ival = 0; |
223 | 0 | unsigned len = it->len; |
224 | 0 | unsigned char *cp = it->data; |
225 | 0 | unsigned long overflow = 0xffUL << ((sizeof(ival) - 1) * 8); |
226 | |
|
227 | 0 | PORT_Assert(len); |
228 | 0 | if (!len) { |
229 | 0 | PORT_SetError(SEC_ERROR_INPUT_LEN); |
230 | 0 | return 0; |
231 | 0 | } |
232 | | |
233 | | /* Cannot put a negative value into an unsigned container. */ |
234 | 0 | if (*cp & 0x80) { |
235 | 0 | PORT_SetError(SEC_ERROR_BAD_DER); |
236 | 0 | return 0; |
237 | 0 | } |
238 | | |
239 | 0 | while (len) { |
240 | 0 | if (ival & overflow) { |
241 | 0 | PORT_SetError(SEC_ERROR_BAD_DER); |
242 | 0 | return ULONG_MAX; |
243 | 0 | } |
244 | 0 | ival = ival << 8; |
245 | 0 | ival |= *cp++; |
246 | 0 | --len; |
247 | 0 | } |
248 | 0 | return ival; |
249 | 0 | } |