]>
git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_keychain/libDER/libDER/DER_Encode.c
bd8e607a6f7410a969d6e3796efad591ce8213b1
2 * Copyright (c) 2005-2016 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
= (DERByte
)(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
);
183 // Silence unused variable warning.
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
193 DERShort numItems
, /* size of itemSpecs[] */
194 const DERItemSpec
*itemSpecs
)
196 DERSize contentLen
= 0;
198 DERSize thisContentLen
;
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
;
207 if(currOptions
& DER_ENC_WRITE_DER
) {
208 /* easy case - no encode */
209 contentLen
+= itemSrc
->length
;
213 if ((currOptions
& DER_DEC_OPTIONAL
) && itemSrc
->length
== 0) {
214 /* If an optional item isn't present we don't encode a
220 * length of this item =
224 * optional zero byte for signed integer
226 contentLen
+= DERLengthOfTag(currItemSpec
->tag
);
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 */
237 contentLen
+= DERLengthOfLength(thisContentLen
);
238 contentLen
+= thisContentLen
;
243 DERReturn
DEREncodeSequence(
244 DERTag topTag
, /* ASN1_CONSTR_SEQUENCE, ASN1_CONSTR_SET */
245 const void *src
, /* generally a ptr to a struct full of
247 DERShort numItems
, /* size of itemSpecs[] */
248 const DERItemSpec
*itemSpecs
,
249 DERByte
*derOut
, /* encoded data written here */
250 DERSize
*inOutLen
) /* IN/OUT */
252 const DERByte
*endPtr
= derOut
+ *inOutLen
;
253 DERByte
*currPtr
= derOut
;
254 DERSize bytesLeft
= *inOutLen
;
262 drtn
= DEREncodeTag(topTag
, currPtr
, &itemLen
);
267 bytesLeft
-= itemLen
;
268 if(currPtr
>= endPtr
) {
269 return DR_BufOverflow
;
273 contentLen
= DERContentLengthOfEncodedSequence(src
, numItems
, itemSpecs
);
275 drtn
= DEREncodeLength(contentLen
, currPtr
, &itemLen
);
280 bytesLeft
-= itemLen
;
281 if(currPtr
+ contentLen
> endPtr
) {
282 return DR_BufOverflow
;
284 /* we don't have to check for overflow any more */
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
;
294 if(currOptions
& DER_ENC_WRITE_DER
) {
296 DERMemmove(currPtr
, itemSrc
->data
, itemSrc
->length
);
297 currPtr
+= itemSrc
->length
;
298 bytesLeft
-= itemSrc
->length
;
302 if ((currOptions
& DER_DEC_OPTIONAL
) && itemSrc
->length
== 0) {
303 /* If an optional item isn't present we skip it. */
307 /* encode one item: first the tag */
309 drtn
= DEREncodeTag(currItemSpec
->tag
, currPtr
, &itemLen
);
314 bytesLeft
-= itemLen
;
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 */
327 /* encode content length */
329 drtn
= DEREncodeLength(contentLen
, currPtr
, &itemLen
);
334 bytesLeft
-= itemLen
;
336 /* now the content, with possible leading zero added */
341 DERMemmove(currPtr
, itemSrc
->data
, itemSrc
->length
);
342 currPtr
+= itemSrc
->length
;
343 bytesLeft
-= itemSrc
->length
;
345 *inOutLen
= (DERSize
)(currPtr
- derOut
);
349 /* calculate the length of an encoded sequence. */
350 DERSize
DERLengthOfEncodedSequence(
352 const void *src
, /* generally a ptr to a struct full of
354 DERShort numItems
, /* size of itemSpecs[] */
355 const DERItemSpec
*itemSpecs
)
357 DERSize contentLen
= DERContentLengthOfEncodedSequence(
358 src
, numItems
, itemSpecs
);
360 return DERLengthOfTag(topTag
) +
361 DERLengthOfLength(contentLen
) +
365 #endif /* DER_ENCODE_ENABLE */