]> git.saurik.com Git - apple/security.git/blob - libsecurity_keychain/libDER/libDER/DER_Encode.c
Security-55179.13.tar.gz
[apple/security.git] / libsecurity_keychain / libDER / libDER / DER_Encode.c
1 /* Copyright (c) 2005-2007 Apple Inc. All Rights Reserved. */
2
3 /*
4 * DER_Encode.h - DER encoding routines
5 *
6 * Created Dec. 2 2005 by dmitch
7 */
8
9 #include <libDER/DER_Encode.h>
10 #include <libDER/asn1Types.h>
11 #include <libDER/libDER_config.h>
12 #include <libDER/DER_Decode.h>
13
14 #ifndef DER_ENCODE_ENABLE
15 #error Please define DER_ENCODE_ENABLE.
16 #endif
17
18 #if DER_ENCODE_ENABLE
19
20 /* calculate size of encoded tag */
21 static DERSize DERLengthOfTag(
22 DERTag tag)
23 {
24 DERSize rtn = 1;
25
26 tag &= ASN1_TAGNUM_MASK;
27 if (tag >= 0x1F) {
28 /* Shift 7-bit digits out of the tag integer until it's zero. */
29 while(tag != 0) {
30 rtn++;
31 tag >>= 7;
32 }
33 }
34
35 return rtn;
36 }
37
38 /* encode tag */
39 static DERReturn DEREncodeTag(
40 DERTag tag,
41 DERByte *buf, /* encoded length goes here */
42 DERSize *inOutLen) /* IN/OUT */
43 {
44 DERSize outLen = DERLengthOfTag(tag);
45 DERTag tagNumber = tag & ASN1_TAGNUM_MASK;
46 DERByte tag1 = (tag >> (sizeof(DERTag) * 8 - 8)) & 0xE0;
47
48 if(outLen > *inOutLen) {
49 return DR_BufOverflow;
50 }
51
52 if(outLen == 1) {
53 /* short form */
54 *buf = tag1 | tagNumber;
55 }
56 else {
57 /* long form */
58 DERByte *tagBytes = buf + outLen; // l.s. digit of tag
59 *buf = tag1 | 0x1F; // tag class / method indicator
60 *--tagBytes = tagNumber & 0x7F;
61 tagNumber >>= 7;
62 while(tagNumber != 0) {
63 *--tagBytes = (tagNumber & 0x7F) | 0x80;
64 tagNumber >>= 7;
65 }
66 }
67 *inOutLen = outLen;
68 return DR_Success;
69 }
70
71 /* calculate size of encoded length */
72 DERSize DERLengthOfLength(
73 DERSize length)
74 {
75 DERSize rtn;
76
77 if(length < 0x80) {
78 /* short form length */
79 return 1;
80 }
81
82 /* long form - one length-of-length byte plus length bytes */
83 rtn = 1;
84 while(length != 0) {
85 rtn++;
86 length >>= 8;
87 }
88 return rtn;
89 }
90
91 /* encode length */
92 DERReturn DEREncodeLength(
93 DERSize length,
94 DERByte *buf, /* encoded length goes here */
95 DERSize *inOutLen) /* IN/OUT */
96 {
97 DERByte *lenBytes;
98 DERSize outLen = DERLengthOfLength(length);
99
100 if(outLen > *inOutLen) {
101 return DR_BufOverflow;
102 }
103
104 if(length < 0x80) {
105 /* short form */
106 *buf = (DERByte)length;
107 *inOutLen = 1;
108 return DR_Success;
109 }
110
111 /* long form */
112 *buf = (outLen - 1) | 0x80; // length of length, long form indicator
113 lenBytes = buf + outLen - 1; // l.s. digit of length
114 while(length != 0) {
115 *lenBytes-- = (DERByte)length;
116 length >>= 8;
117 }
118 *inOutLen = outLen;
119 return DR_Success;
120 }
121
122 DERSize DERLengthOfItem(
123 DERTag tag,
124 DERSize length)
125 {
126 return DERLengthOfTag(tag) + DERLengthOfLength(length) + length;
127 }
128
129 DERReturn DEREncodeItem(
130 DERTag tag,
131 DERSize length,
132 const DERByte *src,
133 DERByte *derOut, /* encoded item goes here */
134 DERSize *inOutLen) /* IN/OUT */
135 {
136 DERReturn drtn;
137 DERSize itemLen;
138 DERByte *currPtr = derOut;
139 DERSize bytesLeft = DERLengthOfItem(tag, length);
140 if(bytesLeft > *inOutLen) {
141 return DR_BufOverflow;
142 }
143 *inOutLen = bytesLeft;
144
145 /* top level tag */
146 itemLen = bytesLeft;
147 drtn = DEREncodeTag(tag, currPtr, &itemLen);
148 if(drtn) {
149 return drtn;
150 }
151 currPtr += itemLen;
152 bytesLeft -= itemLen;
153 itemLen = bytesLeft;
154 drtn = DEREncodeLength(length, currPtr, &itemLen);
155 if(drtn) {
156 return drtn;
157 }
158 currPtr += itemLen;
159 bytesLeft -= itemLen;
160 DERMemmove(currPtr, src, length);
161
162 return DR_Success;
163 }
164
165 static /* calculate the content length of an encoded sequence */
166 DERSize DERContentLengthOfEncodedSequence(
167 const void *src, /* generally a ptr to a struct full of
168 * DERItems */
169 DERShort numItems, /* size of itemSpecs[] */
170 const DERItemSpec *itemSpecs)
171 {
172 DERSize contentLen = 0;
173 unsigned dex;
174 DERSize thisContentLen;
175
176 /* find length of each item */
177 for(dex=0; dex<numItems; dex++) {
178 const DERItemSpec *currItemSpec = &itemSpecs[dex];
179 DERShort currOptions = currItemSpec->options;
180 const DERByte *byteSrc = (const DERByte *)src + currItemSpec->offset;
181 const DERItem *itemSrc = (const DERItem *)byteSrc;
182
183 if(currOptions & DER_ENC_WRITE_DER) {
184 /* easy case - no encode */
185 contentLen += itemSrc->length;
186 continue;
187 }
188
189 if ((currOptions & DER_DEC_OPTIONAL) && itemSrc->length == 0) {
190 /* If an optional item isn't present we don't encode a
191 tag and len. */
192 continue;
193 }
194
195 /*
196 * length of this item =
197 * tag (one byte) +
198 * length of length +
199 * content length +
200 * optional zero byte for signed integer
201 */
202 contentLen += DERLengthOfTag(currItemSpec->tag);
203
204 /* check need for pad byte before calculating lengthOfLength... */
205 thisContentLen = itemSrc->length;
206 if((currOptions & DER_ENC_SIGNED_INT) &&
207 (itemSrc->length != 0)) {
208 if(itemSrc->data[0] & 0x80) {
209 /* insert zero keep it positive */
210 thisContentLen++;
211 }
212 }
213 contentLen += DERLengthOfLength(thisContentLen);
214 contentLen += thisContentLen;
215 }
216 return contentLen;
217 }
218
219 DERReturn DEREncodeSequence(
220 DERTag topTag, /* ASN1_CONSTR_SEQUENCE, ASN1_CONSTR_SET */
221 const void *src, /* generally a ptr to a struct full of
222 * DERItems */
223 DERShort numItems, /* size of itemSpecs[] */
224 const DERItemSpec *itemSpecs,
225 DERByte *derOut, /* encoded data written here */
226 DERSize *inOutLen) /* IN/OUT */
227 {
228 const DERByte *endPtr = derOut + *inOutLen;
229 DERByte *currPtr = derOut;
230 DERSize bytesLeft = *inOutLen;
231 DERSize contentLen;
232 DERReturn drtn;
233 DERSize itemLen;
234 unsigned dex;
235
236 /* top level tag */
237 itemLen = bytesLeft;
238 drtn = DEREncodeTag(topTag, currPtr, &itemLen);
239 if(drtn) {
240 return drtn;
241 }
242 currPtr += itemLen;
243 bytesLeft -= itemLen;
244 if(currPtr >= endPtr) {
245 return DR_BufOverflow;
246 }
247
248 /* content length */
249 contentLen = DERContentLengthOfEncodedSequence(src, numItems, itemSpecs);
250 itemLen = bytesLeft;
251 drtn = DEREncodeLength(contentLen, currPtr, &itemLen);
252 if(drtn) {
253 return drtn;
254 }
255 currPtr += itemLen;
256 bytesLeft -= itemLen;
257 if(currPtr + contentLen > endPtr) {
258 return DR_BufOverflow;
259 }
260 /* we don't have to check for overflow any more */
261
262 /* grind thru the items */
263 for(dex=0; dex<numItems; dex++) {
264 const DERItemSpec *currItemSpec = &itemSpecs[dex];
265 DERShort currOptions = currItemSpec->options;
266 const DERByte *byteSrc = (const DERByte *)src + currItemSpec->offset;
267 const DERItem *itemSrc = (const DERItem *)byteSrc;
268 int prependZero = 0;
269
270 if(currOptions & DER_ENC_WRITE_DER) {
271 /* easy case */
272 DERMemmove(currPtr, itemSrc->data, itemSrc->length);
273 currPtr += itemSrc->length;
274 bytesLeft -= itemSrc->length;
275 continue;
276 }
277
278 if ((currOptions & DER_DEC_OPTIONAL) && itemSrc->length == 0) {
279 /* If an optional item isn't present we skip it. */
280 continue;
281 }
282
283 /* encode one item: first the tag */
284 itemLen = bytesLeft;
285 drtn = DEREncodeTag(currItemSpec->tag, currPtr, &itemLen);
286 if(drtn) {
287 return drtn;
288 }
289 currPtr += itemLen;
290 bytesLeft -= itemLen;
291
292 /* do we need to prepend a zero to content? */
293 contentLen = itemSrc->length;
294 if((currOptions & DER_ENC_SIGNED_INT) &&
295 (itemSrc->length != 0)) {
296 if(itemSrc->data[0] & 0x80) {
297 /* insert zero keep it positive */
298 contentLen++;
299 prependZero = 1;
300 }
301 }
302
303 /* encode content length */
304 itemLen = bytesLeft;
305 drtn = DEREncodeLength(contentLen, currPtr, &itemLen);
306 if(drtn) {
307 return drtn;
308 }
309 currPtr += itemLen;
310 bytesLeft -= itemLen;
311
312 /* now the content, with possible leading zero added */
313 if(prependZero) {
314 *currPtr++ = 0;
315 bytesLeft--;
316 }
317 DERMemmove(currPtr, itemSrc->data, itemSrc->length);
318 currPtr += itemSrc->length;
319 bytesLeft -= itemSrc->length;
320 }
321 *inOutLen = (currPtr - derOut);
322 return DR_Success;
323 }
324
325 /* calculate the length of an encoded sequence. */
326 DERSize DERLengthOfEncodedSequence(
327 DERTag topTag,
328 const void *src, /* generally a ptr to a struct full of
329 * DERItems */
330 DERShort numItems, /* size of itemSpecs[] */
331 const DERItemSpec *itemSpecs)
332 {
333 DERSize contentLen = DERContentLengthOfEncodedSequence(
334 src, numItems, itemSpecs);
335
336 return DERLengthOfTag(topTag) +
337 DERLengthOfLength(contentLen) +
338 contentLen;
339 }
340
341 #endif /* DER_ENCODE_ENABLE */
342