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