]>
git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_keychain/libDER/libDER/DER_Encode.c
9b6946175a0855d0472ca721ee6e7670fe75ee42
2 * Copyright (c) 2005-2007,2011,2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
26 * DER_Encode.h - DER encoding routines
30 #include <libDER/DER_Encode.h>
31 #include <libDER/asn1Types.h>
32 #include <libDER/libDER_config.h>
33 #include <libDER/DER_Decode.h>
35 #ifndef DER_ENCODE_ENABLE
36 #error Please define DER_ENCODE_ENABLE.
41 /* calculate size of encoded tag */
42 static DERSize
DERLengthOfTag(
47 tag
&= ASN1_TAGNUM_MASK
;
49 /* Shift 7-bit digits out of the tag integer until it's zero. */
60 static DERReturn
DEREncodeTag(
62 DERByte
*buf
, /* encoded length goes here */
63 DERSize
*inOutLen
) /* IN/OUT */
65 DERSize outLen
= DERLengthOfTag(tag
);
66 DERTag tagNumber
= tag
& ASN1_TAGNUM_MASK
;
67 DERByte tag1
= (tag
>> (sizeof(DERTag
) * 8 - 8)) & 0xE0;
69 if(outLen
> *inOutLen
) {
70 return DR_BufOverflow
;
75 *buf
= tag1
| tagNumber
;
79 DERByte
*tagBytes
= buf
+ outLen
; // l.s. digit of tag
80 *buf
= tag1
| 0x1F; // tag class / method indicator
81 *--tagBytes
= tagNumber
& 0x7F;
83 while(tagNumber
!= 0) {
84 *--tagBytes
= (tagNumber
& 0x7F) | 0x80;
92 /* calculate size of encoded length */
93 DERSize
DERLengthOfLength(
99 /* short form length */
103 /* long form - one length-of-length byte plus length bytes */
113 DERReturn
DEREncodeLength(
115 DERByte
*buf
, /* encoded length goes here */
116 DERSize
*inOutLen
) /* IN/OUT */
119 DERSize outLen
= DERLengthOfLength(length
);
121 if(outLen
> *inOutLen
) {
122 return DR_BufOverflow
;
127 *buf
= (DERByte
)length
;
133 *buf
= (outLen
- 1) | 0x80; // length of length, long form indicator
134 lenBytes
= buf
+ outLen
- 1; // l.s. digit of length
136 *lenBytes
-- = (DERByte
)length
;
143 DERSize
DERLengthOfItem(
147 return DERLengthOfTag(tag
) + DERLengthOfLength(length
) + length
;
150 DERReturn
DEREncodeItem(
154 DERByte
*derOut
, /* encoded item goes here */
155 DERSize
*inOutLen
) /* IN/OUT */
159 DERByte
*currPtr
= derOut
;
160 DERSize bytesLeft
= DERLengthOfItem(tag
, length
);
161 if(bytesLeft
> *inOutLen
) {
162 return DR_BufOverflow
;
164 *inOutLen
= bytesLeft
;
168 drtn
= DEREncodeTag(tag
, currPtr
, &itemLen
);
173 bytesLeft
-= itemLen
;
175 drtn
= DEREncodeLength(length
, currPtr
, &itemLen
);
180 bytesLeft
-= itemLen
;
181 DERMemmove(currPtr
, src
, length
);
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
192 DERShort numItems
, /* size of itemSpecs[] */
193 const DERItemSpec
*itemSpecs
)
195 DERSize contentLen
= 0;
197 DERSize thisContentLen
;
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
;
206 if(currOptions
& DER_ENC_WRITE_DER
) {
207 /* easy case - no encode */
208 contentLen
+= itemSrc
->length
;
212 if ((currOptions
& DER_DEC_OPTIONAL
) && itemSrc
->length
== 0) {
213 /* If an optional item isn't present we don't encode a
219 * length of this item =
223 * optional zero byte for signed integer
225 contentLen
+= DERLengthOfTag(currItemSpec
->tag
);
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 */
236 contentLen
+= DERLengthOfLength(thisContentLen
);
237 contentLen
+= thisContentLen
;
242 DERReturn
DEREncodeSequence(
243 DERTag topTag
, /* ASN1_CONSTR_SEQUENCE, ASN1_CONSTR_SET */
244 const void *src
, /* generally a ptr to a struct full of
246 DERShort numItems
, /* size of itemSpecs[] */
247 const DERItemSpec
*itemSpecs
,
248 DERByte
*derOut
, /* encoded data written here */
249 DERSize
*inOutLen
) /* IN/OUT */
251 const DERByte
*endPtr
= derOut
+ *inOutLen
;
252 DERByte
*currPtr
= derOut
;
253 DERSize bytesLeft
= *inOutLen
;
261 drtn
= DEREncodeTag(topTag
, currPtr
, &itemLen
);
266 bytesLeft
-= itemLen
;
267 if(currPtr
>= endPtr
) {
268 return DR_BufOverflow
;
272 contentLen
= DERContentLengthOfEncodedSequence(src
, numItems
, itemSpecs
);
274 drtn
= DEREncodeLength(contentLen
, currPtr
, &itemLen
);
279 bytesLeft
-= itemLen
;
280 if(currPtr
+ contentLen
> endPtr
) {
281 return DR_BufOverflow
;
283 /* we don't have to check for overflow any more */
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
;
293 if(currOptions
& DER_ENC_WRITE_DER
) {
295 DERMemmove(currPtr
, itemSrc
->data
, itemSrc
->length
);
296 currPtr
+= itemSrc
->length
;
297 bytesLeft
-= itemSrc
->length
;
301 if ((currOptions
& DER_DEC_OPTIONAL
) && itemSrc
->length
== 0) {
302 /* If an optional item isn't present we skip it. */
306 /* encode one item: first the tag */
308 drtn
= DEREncodeTag(currItemSpec
->tag
, currPtr
, &itemLen
);
313 bytesLeft
-= itemLen
;
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 */
326 /* encode content length */
328 drtn
= DEREncodeLength(contentLen
, currPtr
, &itemLen
);
333 bytesLeft
-= itemLen
;
335 /* now the content, with possible leading zero added */
340 DERMemmove(currPtr
, itemSrc
->data
, itemSrc
->length
);
341 currPtr
+= itemSrc
->length
;
342 bytesLeft
-= itemSrc
->length
;
344 *inOutLen
= (currPtr
- derOut
);
348 /* calculate the length of an encoded sequence. */
349 DERSize
DERLengthOfEncodedSequence(
351 const void *src
, /* generally a ptr to a struct full of
353 DERShort numItems
, /* size of itemSpecs[] */
354 const DERItemSpec
*itemSpecs
)
356 DERSize contentLen
= DERContentLengthOfEncodedSequence(
357 src
, numItems
, itemSpecs
);
359 return DERLengthOfTag(topTag
) +
360 DERLengthOfLength(contentLen
) +
364 #endif /* DER_ENCODE_ENABLE */