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 */ 42static 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 */ 60static 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 */ 93DERSize 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 */ 113DERReturn 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 143DERSize DERLengthOfItem( 144 DERTag tag, 145 DERSize length) 146{ 147 return DERLengthOfTag(tag) + DERLengthOfLength(length) + length; 148} 149 150DERReturn 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 188static /* calculate the content length of an encoded sequence */ 189DERSize 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 242DERReturn 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. */ 349DERSize 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 366