]> git.saurik.com Git - apple/security.git/blobdiff - Security/libsecurity_keychain/libDER/libDER/DER_Encode.c
Security-57031.1.35.tar.gz
[apple/security.git] / Security / libsecurity_keychain / libDER / libDER / DER_Encode.c
diff --git a/Security/libsecurity_keychain/libDER/libDER/DER_Encode.c b/Security/libsecurity_keychain/libDER/libDER/DER_Encode.c
new file mode 100644 (file)
index 0000000..9b69461
--- /dev/null
@@ -0,0 +1,365 @@
+/*
+ * Copyright (c) 2005-2007,2011,2014 Apple Inc. All Rights Reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+/*
+ * DER_Encode.h - DER encoding routines
+ *
+ */
+
+#include <libDER/DER_Encode.h>
+#include <libDER/asn1Types.h>
+#include <libDER/libDER_config.h>
+#include <libDER/DER_Decode.h>
+
+#ifndef        DER_ENCODE_ENABLE
+#error Please define DER_ENCODE_ENABLE.
+#endif
+
+#if            DER_ENCODE_ENABLE
+
+/* calculate size of encoded tag */
+static DERSize DERLengthOfTag(
+       DERTag tag)
+{
+       DERSize rtn = 1;
+
+    tag &= ASN1_TAGNUM_MASK;
+    if (tag >= 0x1F) {
+        /* Shift 7-bit digits out of the tag integer until it's zero. */
+        while(tag != 0) {
+            rtn++;
+            tag >>= 7;
+        }
+    }
+
+    return rtn;
+}
+
+/* encode tag */
+static DERReturn DEREncodeTag(
+       DERTag tag,
+       DERByte *buf,           /* encoded length goes here */
+       DERSize *inOutLen)      /* IN/OUT */
+{
+    DERSize outLen = DERLengthOfTag(tag);
+    DERTag tagNumber = tag & ASN1_TAGNUM_MASK;
+    DERByte tag1 = (tag >> (sizeof(DERTag) * 8 - 8)) & 0xE0;
+
+       if(outLen > *inOutLen) {
+               return DR_BufOverflow;
+       }
+
+    if(outLen == 1) {
+               /* short form */
+               *buf = tag1 | tagNumber;
+       }
+       else {
+        /* long form */
+        DERByte *tagBytes = buf + outLen;      // l.s. digit of tag
+        *buf = tag1 | 0x1F;                 // tag class / method indicator
+        *--tagBytes = tagNumber & 0x7F;
+        tagNumber >>= 7;
+        while(tagNumber != 0) {
+            *--tagBytes = (tagNumber & 0x7F) | 0x80;
+            tagNumber >>= 7;
+        }
+    }
+       *inOutLen = outLen;
+       return DR_Success;
+}
+
+/* calculate size of encoded length */
+DERSize DERLengthOfLength(
+       DERSize length)
+{
+       DERSize rtn;
+       
+       if(length < 0x80) {
+               /* short form length */
+               return 1;
+       }
+       
+       /* long form - one length-of-length byte plus length bytes */
+       rtn = 1;
+       while(length != 0) {
+               rtn++;
+               length >>= 8;
+       }
+       return rtn;
+}
+
+/* encode length */
+DERReturn DEREncodeLength(
+       DERSize length,
+       DERByte *buf,           /* encoded length goes here */
+       DERSize *inOutLen)      /* IN/OUT */
+{
+       DERByte *lenBytes;
+       DERSize outLen = DERLengthOfLength(length);
+       
+       if(outLen > *inOutLen) {
+               return DR_BufOverflow;
+       }
+       
+       if(length < 0x80) {
+               /* short form */
+               *buf = (DERByte)length;
+               *inOutLen = 1;
+               return DR_Success;
+       }
+       
+       /* long form */
+       *buf = (outLen - 1) | 0x80;             // length of length, long form indicator
+       lenBytes = buf + outLen - 1;    // l.s. digit of length 
+       while(length != 0) {
+               *lenBytes-- = (DERByte)length;
+               length >>= 8;
+       }
+       *inOutLen = outLen;
+       return DR_Success;
+}
+
+DERSize DERLengthOfItem(
+       DERTag tag,
+       DERSize length)
+{
+    return DERLengthOfTag(tag) + DERLengthOfLength(length) + length;
+}
+
+DERReturn DEREncodeItem(
+       DERTag tag,
+       DERSize length,
+    const DERByte *src,
+       DERByte *derOut,        /* encoded item goes here */
+       DERSize *inOutLen)      /* IN/OUT */
+{
+       DERReturn               drtn;
+       DERSize                 itemLen;
+       DERByte                 *currPtr = derOut;
+       DERSize         bytesLeft = DERLengthOfItem(tag, length);
+       if(bytesLeft > *inOutLen) {
+               return DR_BufOverflow;
+       }
+       *inOutLen = bytesLeft;
+
+       /* top level tag */
+       itemLen = bytesLeft;
+       drtn = DEREncodeTag(tag, currPtr, &itemLen);
+       if(drtn) {
+               return drtn;
+       }
+       currPtr += itemLen;
+       bytesLeft -= itemLen;
+       itemLen = bytesLeft;
+       drtn = DEREncodeLength(length, currPtr, &itemLen);
+       if(drtn) {
+               return drtn;
+       }
+       currPtr += itemLen;
+       bytesLeft -= itemLen;
+       DERMemmove(currPtr, src, length);
+
+    (void) bytesLeft;
+    
+       return DR_Success;
+}
+
+static /* calculate the content length of an encoded sequence */
+DERSize DERContentLengthOfEncodedSequence(
+       const void                      *src,           /* generally a ptr to a struct full of 
+                                                                        *    DERItems */
+       DERShort                        numItems,       /* size of itemSpecs[] */
+       const DERItemSpec       *itemSpecs)
+{
+       DERSize contentLen = 0;
+       unsigned dex;
+       DERSize thisContentLen;
+       
+       /* find length of each item */
+       for(dex=0; dex<numItems; dex++) {
+               const DERItemSpec *currItemSpec = &itemSpecs[dex];
+               DERShort currOptions = currItemSpec->options;
+               const DERByte *byteSrc = (const DERByte *)src + currItemSpec->offset;
+               const DERItem *itemSrc = (const DERItem *)byteSrc;
+
+               if(currOptions & DER_ENC_WRITE_DER) {
+                       /* easy case - no encode */
+                       contentLen += itemSrc->length;
+                       continue;
+               }
+               
+        if ((currOptions & DER_DEC_OPTIONAL) && itemSrc->length == 0) {
+            /* If an optional item isn't present we don't encode a
+               tag and len. */
+            continue;
+        }
+
+               /* 
+                * length of this item = 
+                *   tag (one byte) +
+                *   length of length +
+                *   content length +
+                *   optional zero byte for signed integer
+                */
+               contentLen += DERLengthOfTag(currItemSpec->tag);
+               
+               /* check need for pad byte before calculating lengthOfLength... */
+               thisContentLen = itemSrc->length;
+               if((currOptions & DER_ENC_SIGNED_INT) &&
+                  (itemSrc->length != 0)) {
+                       if(itemSrc->data[0] & 0x80) {
+                               /* insert zero keep it positive */
+                               thisContentLen++;
+                       }
+               }
+               contentLen += DERLengthOfLength(thisContentLen);
+               contentLen += thisContentLen;
+       }
+       return contentLen;
+}
+
+DERReturn DEREncodeSequence(
+       DERTag                          topTag,         /* ASN1_CONSTR_SEQUENCE, ASN1_CONSTR_SET */
+       const void                      *src,           /* generally a ptr to a struct full of 
+                                                                        *    DERItems */
+       DERShort                        numItems,       /* size of itemSpecs[] */
+       const DERItemSpec       *itemSpecs,
+       DERByte                         *derOut,        /* encoded data written here */
+       DERSize                         *inOutLen)      /* IN/OUT */
+{
+       const DERByte   *endPtr = derOut + *inOutLen;
+       DERByte                 *currPtr = derOut;
+       DERSize                 bytesLeft = *inOutLen;
+       DERSize                 contentLen;
+       DERReturn               drtn;
+       DERSize                 itemLen;
+       unsigned                dex;
+       
+       /* top level tag */
+       itemLen = bytesLeft;
+    drtn = DEREncodeTag(topTag, currPtr, &itemLen);
+       if(drtn) {
+               return drtn;
+       }
+       currPtr += itemLen;
+       bytesLeft -= itemLen;
+       if(currPtr >= endPtr) { 
+               return DR_BufOverflow;
+       }
+       
+       /* content length */
+       contentLen = DERContentLengthOfEncodedSequence(src, numItems, itemSpecs);       
+       itemLen = bytesLeft;
+       drtn = DEREncodeLength(contentLen, currPtr, &itemLen);
+       if(drtn) {
+               return drtn;
+       }
+       currPtr += itemLen;
+       bytesLeft -= itemLen;
+       if(currPtr + contentLen > endPtr) {
+               return DR_BufOverflow;
+       }
+       /* we don't have to check for overflow any more */
+       
+       /* grind thru the items */
+       for(dex=0; dex<numItems; dex++) {
+               const DERItemSpec *currItemSpec = &itemSpecs[dex];
+               DERShort currOptions = currItemSpec->options;
+               const DERByte *byteSrc = (const DERByte *)src + currItemSpec->offset;
+               const DERItem *itemSrc = (const DERItem *)byteSrc;
+               int prependZero = 0;
+               
+               if(currOptions & DER_ENC_WRITE_DER) {
+                       /* easy case */
+                       DERMemmove(currPtr, itemSrc->data, itemSrc->length);
+                       currPtr += itemSrc->length;
+                       bytesLeft -= itemSrc->length;
+                       continue;
+               }
+
+        if ((currOptions & DER_DEC_OPTIONAL) && itemSrc->length == 0) {
+            /* If an optional item isn't present we skip it. */
+            continue;
+        }
+
+        /* encode one item: first the tag */
+        itemLen = bytesLeft;
+        drtn = DEREncodeTag(currItemSpec->tag, currPtr, &itemLen);
+        if(drtn) {
+            return drtn;
+        }
+        currPtr += itemLen;
+        bytesLeft -= itemLen;
+               
+               /* do we need to prepend a zero to content? */
+               contentLen = itemSrc->length;
+               if((currOptions & DER_ENC_SIGNED_INT) &&
+                  (itemSrc->length != 0)) {
+                       if(itemSrc->data[0] & 0x80) {
+                               /* insert zero keep it positive */
+                               contentLen++;
+                               prependZero = 1;
+                       }
+               }
+
+               /* encode content length */
+               itemLen = bytesLeft;
+               drtn = DEREncodeLength(contentLen, currPtr, &itemLen);
+               if(drtn) {
+                       return drtn;
+               }
+               currPtr += itemLen;
+               bytesLeft -= itemLen;
+               
+               /* now the content, with possible leading zero added */
+               if(prependZero) {
+                       *currPtr++ = 0;
+                       bytesLeft--;
+               }
+               DERMemmove(currPtr, itemSrc->data, itemSrc->length);
+               currPtr += itemSrc->length;
+               bytesLeft -= itemSrc->length;
+       }
+       *inOutLen = (currPtr - derOut);
+       return DR_Success;
+}
+
+/* calculate the length of an encoded sequence. */
+DERSize DERLengthOfEncodedSequence(
+    DERTag                             topTag,
+       const void                      *src,           /* generally a ptr to a struct full of 
+                                                                        *    DERItems */
+       DERShort                        numItems,       /* size of itemSpecs[] */
+       const DERItemSpec       *itemSpecs)
+{
+       DERSize contentLen = DERContentLengthOfEncodedSequence(
+               src, numItems, itemSpecs);
+               
+       return DERLengthOfTag(topTag) +
+               DERLengthOfLength(contentLen) +
+               contentLen;
+}
+
+#endif /* DER_ENCODE_ENABLE */
+