/********************************************************************************/ /* */ /* TPM ASN.1 */ /* Written by Ken Goldman */ /* IBM Thomas J. Watson Research Center */ /* $Id: TpmAsn1.c 1519 2019-11-15 20:43:51Z kgoldman $ */ /* */ /* Licenses and Notices */ /* */ /* 1. Copyright Licenses: */ /* */ /* - Trusted Computing Group (TCG) grants to the user of the source code in */ /* this specification (the "Source Code") a worldwide, irrevocable, */ /* nonexclusive, royalty free, copyright license to reproduce, create */ /* derivative works, distribute, display and perform the Source Code and */ /* derivative works thereof, and to grant others the rights granted herein. */ /* */ /* - The TCG grants to the user of the other parts of the specification */ /* (other than the Source Code) the rights to reproduce, distribute, */ /* display, and perform the specification solely for the purpose of */ /* developing products based on such documents. */ /* */ /* 2. Source Code Distribution Conditions: */ /* */ /* - Redistributions of Source Code must retain the above copyright licenses, */ /* this list of conditions and the following disclaimers. */ /* */ /* - Redistributions in binary form must reproduce the above copyright */ /* licenses, this list of conditions and the following disclaimers in the */ /* documentation and/or other materials provided with the distribution. */ /* */ /* 3. Disclaimers: */ /* */ /* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ /* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ /* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ /* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ /* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ /* information on specification licensing rights available through TCG */ /* membership agreements. */ /* */ /* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ /* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ /* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ /* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ /* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ /* */ /* - Without limitation, TCG and its members and licensors disclaim all */ /* liability, including liability for infringement of any proprietary */ /* rights, relating to use of information in this specification and to the */ /* implementation of this specification, and TCG disclaims all liability for */ /* cost of procurement of substitute goods or services, lost profits, loss */ /* of use, loss of data or any incidental, consequential, direct, indirect, */ /* or special damages, whether under contract, tort, warranty or otherwise, */ /* arising in any way out of use or reliance upon this specification or any */ /* information herein. */ /* */ /* (c) Copyright IBM Corp. and others, 2019 */ /* */ /********************************************************************************/ /* 10.2.23 TpmAsn1.c */ /* 10.2.23.1 Includes */ #include "Tpm.h" #define _OIDS_ #include "OIDs.h" #include "TpmAsn1.h" #include "TpmAsn1_fp.h" /* 10.2.23.2 Unmarshaling Functions */ /* 10.2.23.2.1 ASN1UnmarshalContextInitialize() */ /* Function does standard initialization of a context. */ /* Return Value Meaning */ /* TRUE(1) success */ /* FALSE(0) failure */ BOOL ASN1UnmarshalContextInitialize( ASN1UnmarshalContext *ctx, INT16 size, BYTE *buffer ) { VERIFY(buffer != NULL); VERIFY(size > 0); ctx->buffer = buffer; ctx->size = size; ctx->offset = 0; ctx->tag = 0xFF; return TRUE; Error: return FALSE; } /* 10.2.23.2.2 ASN1DecodeLength() */ /* This function extracts the length of an element from buffer starting at offset. */ /* Return Value Meaning */ /* >=0 the extracted length */ /* <0 an error */ INT16 ASN1DecodeLength( ASN1UnmarshalContext *ctx ) { BYTE first; // Next octet in buffer INT16 value; // VERIFY(ctx->offset < ctx->size); first = NEXT_OCTET(ctx); // If the number of octets of the entity is larger than 127, then the first octet // is the number of octets in the length specifier. if(first >= 0x80) { // Make sure that this length field is contained with the structure being // parsed CHECK_SIZE(ctx, (first & 0x7F)); if(first == 0x82) { // Two octets of size // get the next value value = (INT16)NEXT_OCTET(ctx); // Make sure that the result will fit in an INT16 VERIFY(value < 0x0080); // Shift up and add next octet value = (value << 8) + NEXT_OCTET(ctx); } else if(first == 0x81) value = NEXT_OCTET(ctx); // Sizes larger than will fit in a INT16 are an error else goto Error; } else value = first; // Make sure that the size defined something within the current context CHECK_SIZE(ctx, value); return value; Error: ctx->size = -1; // Makes everything fail from now on. return -1; } /* 10.2.23.2.3 ASN1NextTag() */ /* This function extracts the next type from buffer starting at offset. It advances offset as it parses the type and the length of the type. It returns the length of the type. On return, the length octets starting at offset are the octets of the type. */ /* Return Value Meaning */ /* >=0 the number of octets in type */ /* <0 an error */ INT16 ASN1NextTag( ASN1UnmarshalContext *ctx ) { // A tag to get? VERIFY(ctx->offset < ctx->size); // Get it ctx->tag = NEXT_OCTET(ctx); // Make sure that it is not an extended tag VERIFY((ctx->tag & 0x1F) != 0x1F); // Get the length field and return that return ASN1DecodeLength(ctx); Error: // Attempt to read beyond the end of the context or an illegal tag ctx->size = -1; // Persistent failure ctx->tag = 0xFF; return -1; } /* 10.2.23.2.4 ASN1GetBitStringValue() */ /* Try to parse a bit string of up to 32 bits from a value that is expected to be a bit string. The bit string is left justified so that the MSb of the input is the MSb of the returned value. If there is a general parsing error, the context->size is set to -1. */ /* Return Value Meaning */ /* TRUE(1) success */ /* FALSE(0) failure */ BOOL ASN1GetBitStringValue( ASN1UnmarshalContext *ctx, UINT32 *val ) { int shift; INT16 length; UINT32 value = 0; int inputBits; // length = ASN1NextTag(ctx); VERIFY(length >= 1); VERIFY(ctx->tag == ASN1_BITSTRING); // Get the shift value for the bit field (how many bits to lop off of the end) shift = NEXT_OCTET(ctx); length--; // Get the number of bits in the input inputBits = (8 * length) - shift; // the shift count has to make sense VERIFY((shift < 8) && ((length > 0) || (shift == 0))); // if there are any bytes left for(; length > 1; length--) { // for all but the last octet, just shift and add the new octet VERIFY((value & 0xFF000000) == 0); // can't loose significant bits value = (value << 8) + NEXT_OCTET(ctx); } if(length == 1) { // for the last octet, just shift the accumulated value enough to // accept the significant bits in the last octet and shift the last // octet down VERIFY(((value & (0xFF000000 << (8 - shift)))) == 0); value = (value << (8 - shift)) + (NEXT_OCTET(ctx) >> shift); } // 'Left justify' the result if(inputBits > 0) value <<= (32 - inputBits); *val = value; return TRUE; Error: ctx->size = -1; return FALSE; } /* 10.2.23.3 Marshaling Functions */ /* 10.2.23.3.1 Introduction */ /* Marshaling of an ASN.1 structure is accomplished from the bottom up. That is, the things that will be at the end of the structure are added last. To manage the collecting of the relative sizes, start a context for the outermost container, if there is one, and then placing items in from the bottom up. If the bottom-most item is also within a structure, create a nested context by calling ASN1StartMarshalingContext(). */ /* The context control structure contains a buffer pointer, an offset, an end and a stack. offset is the offset from the start of the buffer of the last added byte. When offset reaches 0, the buffer is full. offset is a signed value so that, when it becomes negative, there is an overflow. Only two functions are allowed to move bytes into the buffer: ASN1PushByte() and ASN1PushBytes(). These functions make sure that no data is written beyond the end of the buffer. */ /* When a new context is started, the current value of end is pushed on the stack and end is set to 'offset. As bytes are added, offset gets smaller. At any time, the count of bytes in the current context is simply end - offset. */ /* Since starting a new context involves setting end = offset, the number of bytes in the context starts at 0. The nominal way of ending a context is to use end - offset to set the length value, and then a tag is added to the buffer. Then the previous end value is popped meaning that the context just ended becomes a member of the now current context. */ /* The nominal strategy for building a completed ASN.1 structure is to push everything into the buffer and then move everything to the start of the buffer. The move is simple as the size of the move is the initial end value minus the final offset value. The destination is buffer and the source is buffer + offset. As Skippy would say "Easy peasy, Joe." */ /* It is not necessary to provide a buffer into which the data is placed. If no buffer is provided, then the marshaling process will return values needed for marshaling. On strategy for filling the buffer would be to execute the process for building the structure without using a buffer. This would return the overall size of the structure. Then that amount of data could be allocated for the buffer and the fill process executed again with the data going into the buffer. At the end, the data would be in its final resting place. */ /* 10.2.23.3.2 ASN1InitialializeMarshalContext() */ /* This creates a structure for handling marshaling of an ASN.1 formatted data structure. */ void ASN1InitialializeMarshalContext( ASN1MarshalContext *ctx, INT16 length, BYTE *buffer ) { ctx->buffer = buffer; if(buffer) ctx->offset = length; else ctx->offset = INT16_MAX; ctx->end = ctx->offset; ctx->depth = -1; } /* 10.2.23.3.3 ASN1StartMarshalContext() */ /* This starts a new constructed element. It is constructed on top of the value that was previously placed in the structure. */ void ASN1StartMarshalContext( ASN1MarshalContext *ctx ) { pAssert((ctx->depth + 1) < MAX_DEPTH); ctx->depth++; ctx->ends[ctx->depth] = ctx->end; ctx->end = ctx->offset; } /* 10.2.23.3.4 ASN1EndMarshalContext() */ /* This function restores the end pointer for an encapsulating structure. */ /* Return Value Meaning */ /* > 0 the size of the encapsulated structure that was just ended */ /* <= 0 an error */ INT16 ASN1EndMarshalContext( ASN1MarshalContext *ctx ) { INT16 length; pAssert(ctx->depth >= 0); length = ctx->end - ctx->offset; ctx->end = ctx->ends[ctx->depth--]; if((ctx->depth == -1) && (ctx->buffer)) { MemoryCopy(ctx->buffer, ctx->buffer + ctx->offset, ctx->end - ctx->offset); } return length; } /* 10.2.23.3.5 ASN1EndEncapsulation() */ /* This function puts a tag and length in the buffer. In this function, an embedded BIT_STRING is assumed to be a collection of octets. To indicate that all bits are used, a byte of zero is prepended. If a raw bit-string is needed, a new function like ASN1PushInteger() would be needed. */ /* Return Value Meaning */ /* > 0 number of octets in the encapsulation */ /* == 0 failure */ UINT16 ASN1EndEncapsulation( ASN1MarshalContext *ctx, BYTE tag ) { // only add a leading zero for an encapsulated BIT STRING if (tag == ASN1_BITSTRING) ASN1PushByte(ctx, 0); ASN1PushTagAndLength(ctx, tag, ctx->end - ctx->offset); return ASN1EndMarshalContext(ctx); } /* 10.2.23.3.6 ASN1PushByte() */ BOOL ASN1PushByte( ASN1MarshalContext *ctx, BYTE b ) { if(ctx->offset > 0) { ctx->offset -= 1; if(ctx->buffer) ctx->buffer[ctx->offset] = b; return TRUE; } ctx->offset = -1; return FALSE; } /* 10.2.23.3.7 ASN1PushBytes() */ /* Push some raw bytes onto the buffer. count cannot be zero. */ /* Return Value Meaning */ /* > 0 count bytes */ /* == 0 failure unless count was zero */ INT16 ASN1PushBytes( ASN1MarshalContext *ctx, INT16 count, const BYTE *buffer ) { // make sure that count is not negative which would mess up the math; and that // if there is a count, there is a buffer VERIFY((count >= 0) && ((buffer != NULL) || (count == 0))); // back up the offset to determine where the new octets will get pushed ctx->offset -= count; // can't go negative VERIFY(ctx->offset >= 0); // if there are buffers, move the data, otherwise, assume that this is just a // test. if(count && buffer && ctx->buffer) MemoryCopy(&ctx->buffer[ctx->offset], buffer, count); return count; Error: ctx->offset = -1; return 0; } /* 10.2.23.3.8 ASN1PushNull() */ /* Return Value Meaning */ /* > 0 count bytes */ /* == 0 failure unless count was zero */ INT16 ASN1PushNull( ASN1MarshalContext *ctx ) { ASN1PushByte(ctx, 0); ASN1PushByte(ctx, ASN1_NULL); return (ctx->offset >= 0) ? 2 : 0; } /* 10.2.23.3.9 ASN1PushLength() */ /* Push a length value. This will only handle length values that fit in an INT16. */ /* Return Value Meaning */ /* > 0 number of bytes added */ /* == 0 failure */ INT16 ASN1PushLength( ASN1MarshalContext *ctx, INT16 len ) { UINT16 start = ctx->offset; VERIFY(len >= 0); if(len <= 127) ASN1PushByte(ctx, (BYTE)len); else { ASN1PushByte(ctx, (BYTE)(len & 0xFF)); len >>= 8; if(len == 0) ASN1PushByte(ctx, 0x81); else { ASN1PushByte(ctx, (BYTE)(len)); ASN1PushByte(ctx, 0x82); } } goto Exit; Error: ctx->offset = -1; Exit: return (ctx->offset > 0) ? start - ctx->offset : 0; } /* 10.2.23.3.10 ASN1PushTagAndLength() */ /* Return Value Meaning */ /* > 0 number of bytes added */ /* == 0 failure */ INT16 ASN1PushTagAndLength( ASN1MarshalContext *ctx, BYTE tag, INT16 length ) { INT16 bytes; bytes = ASN1PushLength(ctx, length); bytes += (INT16)ASN1PushByte(ctx, tag); return (ctx->offset < 0) ? 0 : bytes; } /* 10.2.23.3.11 ASN1PushTaggedOctetString() */ /* This function will push a random octet string. */ /* Return Value Meaning */ /* > 0 number of bytes added */ /* == 0 failure */ INT16 ASN1PushTaggedOctetString( ASN1MarshalContext *ctx, INT16 size, const BYTE *string, BYTE tag ) { ASN1PushBytes(ctx, size, string); // PushTagAndLenght just tells how many octets it added so the total size of this // element is the sum of those octets and input size. size += ASN1PushTagAndLength(ctx, tag, size); return size; } /* 10.2.23.3.12 ASN1PushUINT() */ /* This function pushes an native-endian integer value. This just changes a native-endian integer into a big-endian byte string and calls ASN1PushInteger(). That function will remove leading zeros and make sure that the number is positive. */ /* Return Value Meaning */ /* > 0 count bytes */ /* == 0 failure unless count was zero */ INT16 ASN1PushUINT( ASN1MarshalContext *ctx, UINT32 integer ) { BYTE marshaled[4]; UINT32_TO_BYTE_ARRAY(integer, marshaled); return ASN1PushInteger(ctx, 4, marshaled); } /* 10.2.23.3.13 ASN1PushInteger */ /* Push a big-endian integer on the end of the buffer */ /* Return Value Meaning */ /* > 0 the number of bytes marshaled for the integer */ /* == 0 failure */ INT16 ASN1PushInteger( ASN1MarshalContext *ctx, // IN/OUT: buffer context INT16 iLen, // IN: octets of the integer BYTE *integer // IN: big-endian integer ) { // no leading 0's while((*integer == 0) && (--iLen > 0)) integer++; // Move the bytes to the buffer ASN1PushBytes(ctx, iLen, integer); // if needed, add a leading byte of 0 to make the number positive if(*integer & 0x80) iLen += (INT16)ASN1PushByte(ctx, 0); // PushTagAndLenght just tells how many octets it added so the total size of this // element is the sum of those octets and the adjusted input size. iLen += ASN1PushTagAndLength(ctx, ASN1_INTEGER, iLen); return iLen; } /* 10.2.23.3.14 ASN1PushOID() */ /* This function is used to add an OID. An OID is 0x06 followed by a byte of size followed by size bytes. This is used to avoid having to do anything special in the definition of an OID. */ /* Return Value Meaning */ /* > 0 the number of bytes marshaled for the integer */ /* == 0 failure */ INT16 ASN1PushOID( ASN1MarshalContext *ctx, const BYTE *OID ) { if((*OID == ASN1_OBJECT_IDENTIFIER) && ((OID[1] & 0x80) == 0)) { return ASN1PushBytes(ctx, OID[1] + 2, OID); } ctx->offset = -1; return 0; }