]>
git.saurik.com Git - apple/security.git/blob - libsecurity_keychain/libDER/libDER/DER_Encode.c
1 /* Copyright (c) 2005-2007 Apple Inc. All Rights Reserved. */
4 * DER_Encode.h - DER encoding routines
6 * Created Dec. 2 2005 by dmitch
9 #include <libDER/DER_Encode.h>
10 #include <libDER/asn1Types.h>
11 #include <libDER/libDER_config.h>
12 #include <libDER/DER_Decode.h>
14 #ifndef DER_ENCODE_ENABLE
15 #error Please define DER_ENCODE_ENABLE.
20 /* calculate size of encoded tag */
21 static DERSize
DERLengthOfTag(
26 tag
&= ASN1_TAGNUM_MASK
;
28 /* Shift 7-bit digits out of the tag integer until it's zero. */
39 static DERReturn
DEREncodeTag(
41 DERByte
*buf
, /* encoded length goes here */
42 DERSize
*inOutLen
) /* IN/OUT */
44 DERSize outLen
= DERLengthOfTag(tag
);
45 DERTag tagNumber
= tag
& ASN1_TAGNUM_MASK
;
46 DERByte tag1
= (tag
>> (sizeof(DERTag
) * 8 - 8)) & 0xE0;
48 if(outLen
> *inOutLen
) {
49 return DR_BufOverflow
;
54 *buf
= tag1
| tagNumber
;
58 DERByte
*tagBytes
= buf
+ outLen
; // l.s. digit of tag
59 *buf
= tag1
| 0x1F; // tag class / method indicator
60 *--tagBytes
= tagNumber
& 0x7F;
62 while(tagNumber
!= 0) {
63 *--tagBytes
= (tagNumber
& 0x7F) | 0x80;
71 /* calculate size of encoded length */
72 DERSize
DERLengthOfLength(
78 /* short form length */
82 /* long form - one length-of-length byte plus length bytes */
92 DERReturn
DEREncodeLength(
94 DERByte
*buf
, /* encoded length goes here */
95 DERSize
*inOutLen
) /* IN/OUT */
98 DERSize outLen
= DERLengthOfLength(length
);
100 if(outLen
> *inOutLen
) {
101 return DR_BufOverflow
;
106 *buf
= (DERByte
)length
;
112 *buf
= (outLen
- 1) | 0x80; // length of length, long form indicator
113 lenBytes
= buf
+ outLen
- 1; // l.s. digit of length
115 *lenBytes
-- = (DERByte
)length
;
122 DERSize
DERLengthOfItem(
126 return DERLengthOfTag(tag
) + DERLengthOfLength(length
) + length
;
129 DERReturn
DEREncodeItem(
133 DERByte
*derOut
, /* encoded item goes here */
134 DERSize
*inOutLen
) /* IN/OUT */
138 DERByte
*currPtr
= derOut
;
139 DERSize bytesLeft
= DERLengthOfItem(tag
, length
);
140 if(bytesLeft
> *inOutLen
) {
141 return DR_BufOverflow
;
143 *inOutLen
= bytesLeft
;
147 drtn
= DEREncodeTag(tag
, currPtr
, &itemLen
);
152 bytesLeft
-= itemLen
;
154 drtn
= DEREncodeLength(length
, currPtr
, &itemLen
);
159 bytesLeft
-= itemLen
;
160 DERMemmove(currPtr
, src
, length
);
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
169 DERShort numItems
, /* size of itemSpecs[] */
170 const DERItemSpec
*itemSpecs
)
172 DERSize contentLen
= 0;
174 DERSize thisContentLen
;
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
;
183 if(currOptions
& DER_ENC_WRITE_DER
) {
184 /* easy case - no encode */
185 contentLen
+= itemSrc
->length
;
189 if ((currOptions
& DER_DEC_OPTIONAL
) && itemSrc
->length
== 0) {
190 /* If an optional item isn't present we don't encode a
196 * length of this item =
200 * optional zero byte for signed integer
202 contentLen
+= DERLengthOfTag(currItemSpec
->tag
);
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 */
213 contentLen
+= DERLengthOfLength(thisContentLen
);
214 contentLen
+= thisContentLen
;
219 DERReturn
DEREncodeSequence(
220 DERTag topTag
, /* ASN1_CONSTR_SEQUENCE, ASN1_CONSTR_SET */
221 const void *src
, /* generally a ptr to a struct full of
223 DERShort numItems
, /* size of itemSpecs[] */
224 const DERItemSpec
*itemSpecs
,
225 DERByte
*derOut
, /* encoded data written here */
226 DERSize
*inOutLen
) /* IN/OUT */
228 const DERByte
*endPtr
= derOut
+ *inOutLen
;
229 DERByte
*currPtr
= derOut
;
230 DERSize bytesLeft
= *inOutLen
;
238 drtn
= DEREncodeTag(topTag
, currPtr
, &itemLen
);
243 bytesLeft
-= itemLen
;
244 if(currPtr
>= endPtr
) {
245 return DR_BufOverflow
;
249 contentLen
= DERContentLengthOfEncodedSequence(src
, numItems
, itemSpecs
);
251 drtn
= DEREncodeLength(contentLen
, currPtr
, &itemLen
);
256 bytesLeft
-= itemLen
;
257 if(currPtr
+ contentLen
> endPtr
) {
258 return DR_BufOverflow
;
260 /* we don't have to check for overflow any more */
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
;
270 if(currOptions
& DER_ENC_WRITE_DER
) {
272 DERMemmove(currPtr
, itemSrc
->data
, itemSrc
->length
);
273 currPtr
+= itemSrc
->length
;
274 bytesLeft
-= itemSrc
->length
;
278 if ((currOptions
& DER_DEC_OPTIONAL
) && itemSrc
->length
== 0) {
279 /* If an optional item isn't present we skip it. */
283 /* encode one item: first the tag */
285 drtn
= DEREncodeTag(currItemSpec
->tag
, currPtr
, &itemLen
);
290 bytesLeft
-= itemLen
;
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 */
303 /* encode content length */
305 drtn
= DEREncodeLength(contentLen
, currPtr
, &itemLen
);
310 bytesLeft
-= itemLen
;
312 /* now the content, with possible leading zero added */
317 DERMemmove(currPtr
, itemSrc
->data
, itemSrc
->length
);
318 currPtr
+= itemSrc
->length
;
319 bytesLeft
-= itemSrc
->length
;
321 *inOutLen
= (currPtr
- derOut
);
325 /* calculate the length of an encoded sequence. */
326 DERSize
DERLengthOfEncodedSequence(
328 const void *src
, /* generally a ptr to a struct full of
330 DERShort numItems
, /* size of itemSpecs[] */
331 const DERItemSpec
*itemSpecs
)
333 DERSize contentLen
= DERContentLengthOfEncodedSequence(
334 src
, numItems
, itemSpecs
);
336 return DERLengthOfTag(topTag
) +
337 DERLengthOfLength(contentLen
) +
341 #endif /* DER_ENCODE_ENABLE */