]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_keychain/libDER/libDER/DER_Encode.c
bd8e607a6f7410a969d6e3796efad591ce8213b1
[apple/security.git] / OSX / libsecurity_keychain / libDER / libDER / DER_Encode.c
1 /*
2 * Copyright (c) 2005-2016 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 = (DERByte)(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 // Silence unused variable warning.
184 (void) bytesLeft;
185
186 return DR_Success;
187 }
188
189 static /* calculate the content length of an encoded sequence */
190 DERSize DERContentLengthOfEncodedSequence(
191 const void *src, /* generally a ptr to a struct full of
192 * DERItems */
193 DERShort numItems, /* size of itemSpecs[] */
194 const DERItemSpec *itemSpecs)
195 {
196 DERSize contentLen = 0;
197 unsigned dex;
198 DERSize thisContentLen;
199
200 /* find length of each item */
201 for(dex=0; dex<numItems; dex++) {
202 const DERItemSpec *currItemSpec = &itemSpecs[dex];
203 DERShort currOptions = currItemSpec->options;
204 const DERByte *byteSrc = (const DERByte *)src + currItemSpec->offset;
205 const DERItem *itemSrc = (const DERItem *)byteSrc;
206
207 if(currOptions & DER_ENC_WRITE_DER) {
208 /* easy case - no encode */
209 contentLen += itemSrc->length;
210 continue;
211 }
212
213 if ((currOptions & DER_DEC_OPTIONAL) && itemSrc->length == 0) {
214 /* If an optional item isn't present we don't encode a
215 tag and len. */
216 continue;
217 }
218
219 /*
220 * length of this item =
221 * tag (one byte) +
222 * length of length +
223 * content length +
224 * optional zero byte for signed integer
225 */
226 contentLen += DERLengthOfTag(currItemSpec->tag);
227
228 /* check need for pad byte before calculating lengthOfLength... */
229 thisContentLen = itemSrc->length;
230 if((currOptions & DER_ENC_SIGNED_INT) &&
231 (itemSrc->length != 0)) {
232 if(itemSrc->data[0] & 0x80) {
233 /* insert zero keep it positive */
234 thisContentLen++;
235 }
236 }
237 contentLen += DERLengthOfLength(thisContentLen);
238 contentLen += thisContentLen;
239 }
240 return contentLen;
241 }
242
243 DERReturn DEREncodeSequence(
244 DERTag topTag, /* ASN1_CONSTR_SEQUENCE, ASN1_CONSTR_SET */
245 const void *src, /* generally a ptr to a struct full of
246 * DERItems */
247 DERShort numItems, /* size of itemSpecs[] */
248 const DERItemSpec *itemSpecs,
249 DERByte *derOut, /* encoded data written here */
250 DERSize *inOutLen) /* IN/OUT */
251 {
252 const DERByte *endPtr = derOut + *inOutLen;
253 DERByte *currPtr = derOut;
254 DERSize bytesLeft = *inOutLen;
255 DERSize contentLen;
256 DERReturn drtn;
257 DERSize itemLen;
258 unsigned dex;
259
260 /* top level tag */
261 itemLen = bytesLeft;
262 drtn = DEREncodeTag(topTag, currPtr, &itemLen);
263 if(drtn) {
264 return drtn;
265 }
266 currPtr += itemLen;
267 bytesLeft -= itemLen;
268 if(currPtr >= endPtr) {
269 return DR_BufOverflow;
270 }
271
272 /* content length */
273 contentLen = DERContentLengthOfEncodedSequence(src, numItems, itemSpecs);
274 itemLen = bytesLeft;
275 drtn = DEREncodeLength(contentLen, currPtr, &itemLen);
276 if(drtn) {
277 return drtn;
278 }
279 currPtr += itemLen;
280 bytesLeft -= itemLen;
281 if(currPtr + contentLen > endPtr) {
282 return DR_BufOverflow;
283 }
284 /* we don't have to check for overflow any more */
285
286 /* grind thru the items */
287 for(dex=0; dex<numItems; dex++) {
288 const DERItemSpec *currItemSpec = &itemSpecs[dex];
289 DERShort currOptions = currItemSpec->options;
290 const DERByte *byteSrc = (const DERByte *)src + currItemSpec->offset;
291 const DERItem *itemSrc = (const DERItem *)byteSrc;
292 int prependZero = 0;
293
294 if(currOptions & DER_ENC_WRITE_DER) {
295 /* easy case */
296 DERMemmove(currPtr, itemSrc->data, itemSrc->length);
297 currPtr += itemSrc->length;
298 bytesLeft -= itemSrc->length;
299 continue;
300 }
301
302 if ((currOptions & DER_DEC_OPTIONAL) && itemSrc->length == 0) {
303 /* If an optional item isn't present we skip it. */
304 continue;
305 }
306
307 /* encode one item: first the tag */
308 itemLen = bytesLeft;
309 drtn = DEREncodeTag(currItemSpec->tag, currPtr, &itemLen);
310 if(drtn) {
311 return drtn;
312 }
313 currPtr += itemLen;
314 bytesLeft -= itemLen;
315
316 /* do we need to prepend a zero to content? */
317 contentLen = itemSrc->length;
318 if((currOptions & DER_ENC_SIGNED_INT) &&
319 (itemSrc->length != 0)) {
320 if(itemSrc->data[0] & 0x80) {
321 /* insert zero keep it positive */
322 contentLen++;
323 prependZero = 1;
324 }
325 }
326
327 /* encode content length */
328 itemLen = bytesLeft;
329 drtn = DEREncodeLength(contentLen, currPtr, &itemLen);
330 if(drtn) {
331 return drtn;
332 }
333 currPtr += itemLen;
334 bytesLeft -= itemLen;
335
336 /* now the content, with possible leading zero added */
337 if(prependZero) {
338 *currPtr++ = 0;
339 bytesLeft--;
340 }
341 DERMemmove(currPtr, itemSrc->data, itemSrc->length);
342 currPtr += itemSrc->length;
343 bytesLeft -= itemSrc->length;
344 }
345 *inOutLen = (DERSize)(currPtr - derOut);
346 return DR_Success;
347 }
348
349 /* calculate the length of an encoded sequence. */
350 DERSize DERLengthOfEncodedSequence(
351 DERTag topTag,
352 const void *src, /* generally a ptr to a struct full of
353 * DERItems */
354 DERShort numItems, /* size of itemSpecs[] */
355 const DERItemSpec *itemSpecs)
356 {
357 DERSize contentLen = DERContentLengthOfEncodedSequence(
358 src, numItems, itemSpecs);
359
360 return DERLengthOfTag(topTag) +
361 DERLengthOfLength(contentLen) +
362 contentLen;
363 }
364
365 #endif /* DER_ENCODE_ENABLE */
366