1*5c591343SA. Cody Schuffelen /* Microsoft Reference Implementation for TPM 2.0
2*5c591343SA. Cody Schuffelen *
3*5c591343SA. Cody Schuffelen * The copyright in this software is being made available under the BSD License,
4*5c591343SA. Cody Schuffelen * included below. This software may be subject to other third party and
5*5c591343SA. Cody Schuffelen * contributor rights, including patent rights, and no such rights are granted
6*5c591343SA. Cody Schuffelen * under this license.
7*5c591343SA. Cody Schuffelen *
8*5c591343SA. Cody Schuffelen * Copyright (c) Microsoft Corporation
9*5c591343SA. Cody Schuffelen *
10*5c591343SA. Cody Schuffelen * All rights reserved.
11*5c591343SA. Cody Schuffelen *
12*5c591343SA. Cody Schuffelen * BSD License
13*5c591343SA. Cody Schuffelen *
14*5c591343SA. Cody Schuffelen * Redistribution and use in source and binary forms, with or without modification,
15*5c591343SA. Cody Schuffelen * are permitted provided that the following conditions are met:
16*5c591343SA. Cody Schuffelen *
17*5c591343SA. Cody Schuffelen * Redistributions of source code must retain the above copyright notice, this list
18*5c591343SA. Cody Schuffelen * of conditions and the following disclaimer.
19*5c591343SA. Cody Schuffelen *
20*5c591343SA. Cody Schuffelen * Redistributions in binary form must reproduce the above copyright notice, this
21*5c591343SA. Cody Schuffelen * list of conditions and the following disclaimer in the documentation and/or
22*5c591343SA. Cody Schuffelen * other materials provided with the distribution.
23*5c591343SA. Cody Schuffelen *
24*5c591343SA. Cody Schuffelen * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS""
25*5c591343SA. Cody Schuffelen * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26*5c591343SA. Cody Schuffelen * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27*5c591343SA. Cody Schuffelen * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
28*5c591343SA. Cody Schuffelen * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29*5c591343SA. Cody Schuffelen * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30*5c591343SA. Cody Schuffelen * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
31*5c591343SA. Cody Schuffelen * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32*5c591343SA. Cody Schuffelen * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33*5c591343SA. Cody Schuffelen * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34*5c591343SA. Cody Schuffelen */
35*5c591343SA. Cody Schuffelen //** Includes
36*5c591343SA. Cody Schuffelen #include "Tpm.h"
37*5c591343SA. Cody Schuffelen #define _OIDS_
38*5c591343SA. Cody Schuffelen #include "OIDs.h"
39*5c591343SA. Cody Schuffelen #include "TpmASN1.h"
40*5c591343SA. Cody Schuffelen #include "TpmASN1_fp.h"
41*5c591343SA. Cody Schuffelen
42*5c591343SA. Cody Schuffelen //** Unmarshaling Functions
43*5c591343SA. Cody Schuffelen
44*5c591343SA. Cody Schuffelen //*** ASN1UnmarshalContextInitialize()
45*5c591343SA. Cody Schuffelen // Function does standard initialization of a context.
46*5c591343SA. Cody Schuffelen // Return Type: BOOL
47*5c591343SA. Cody Schuffelen // TRUE(1) success
48*5c591343SA. Cody Schuffelen // FALSE(0) failure
49*5c591343SA. Cody Schuffelen BOOL
ASN1UnmarshalContextInitialize(ASN1UnmarshalContext * ctx,INT16 size,BYTE * buffer)50*5c591343SA. Cody Schuffelen ASN1UnmarshalContextInitialize(
51*5c591343SA. Cody Schuffelen ASN1UnmarshalContext *ctx,
52*5c591343SA. Cody Schuffelen INT16 size,
53*5c591343SA. Cody Schuffelen BYTE *buffer
54*5c591343SA. Cody Schuffelen )
55*5c591343SA. Cody Schuffelen {
56*5c591343SA. Cody Schuffelen VERIFY(buffer != NULL);
57*5c591343SA. Cody Schuffelen VERIFY(size > 0);
58*5c591343SA. Cody Schuffelen ctx->buffer = buffer;
59*5c591343SA. Cody Schuffelen ctx->size = size;
60*5c591343SA. Cody Schuffelen ctx->offset = 0;
61*5c591343SA. Cody Schuffelen ctx->tag = 0xFF;
62*5c591343SA. Cody Schuffelen return TRUE;
63*5c591343SA. Cody Schuffelen Error:
64*5c591343SA. Cody Schuffelen return FALSE;
65*5c591343SA. Cody Schuffelen }
66*5c591343SA. Cody Schuffelen
67*5c591343SA. Cody Schuffelen //***ASN1DecodeLength()
68*5c591343SA. Cody Schuffelen // This function extracts the length of an element from 'buffer' starting at 'offset'.
69*5c591343SA. Cody Schuffelen // Return Type: UINT16
70*5c591343SA. Cody Schuffelen // >=0 the extracted length
71*5c591343SA. Cody Schuffelen // <0 an error
72*5c591343SA. Cody Schuffelen INT16
ASN1DecodeLength(ASN1UnmarshalContext * ctx)73*5c591343SA. Cody Schuffelen ASN1DecodeLength(
74*5c591343SA. Cody Schuffelen ASN1UnmarshalContext *ctx
75*5c591343SA. Cody Schuffelen )
76*5c591343SA. Cody Schuffelen {
77*5c591343SA. Cody Schuffelen BYTE first; // Next octet in buffer
78*5c591343SA. Cody Schuffelen INT16 value;
79*5c591343SA. Cody Schuffelen //
80*5c591343SA. Cody Schuffelen VERIFY(ctx->offset < ctx->size);
81*5c591343SA. Cody Schuffelen first = NEXT_OCTET(ctx);
82*5c591343SA. Cody Schuffelen // If the number of octets of the entity is larger than 127, then the first octet
83*5c591343SA. Cody Schuffelen // is the number of octets in the length specifier.
84*5c591343SA. Cody Schuffelen if(first >= 0x80)
85*5c591343SA. Cody Schuffelen {
86*5c591343SA. Cody Schuffelen // Make sure that this length field is contained with the structure being
87*5c591343SA. Cody Schuffelen // parsed
88*5c591343SA. Cody Schuffelen CHECK_SIZE(ctx, (first & 0x7F));
89*5c591343SA. Cody Schuffelen if(first == 0x82)
90*5c591343SA. Cody Schuffelen {
91*5c591343SA. Cody Schuffelen // Two octets of size
92*5c591343SA. Cody Schuffelen // get the next value
93*5c591343SA. Cody Schuffelen value = (INT16)NEXT_OCTET(ctx);
94*5c591343SA. Cody Schuffelen // Make sure that the result will fit in an INT16
95*5c591343SA. Cody Schuffelen VERIFY(value < 0x0080);
96*5c591343SA. Cody Schuffelen // Shift up and add next octet
97*5c591343SA. Cody Schuffelen value = (value << 8) + NEXT_OCTET(ctx);
98*5c591343SA. Cody Schuffelen }
99*5c591343SA. Cody Schuffelen else if(first == 0x81)
100*5c591343SA. Cody Schuffelen value = NEXT_OCTET(ctx);
101*5c591343SA. Cody Schuffelen // Sizes larger than will fit in a INT16 are an error
102*5c591343SA. Cody Schuffelen else
103*5c591343SA. Cody Schuffelen goto Error;
104*5c591343SA. Cody Schuffelen }
105*5c591343SA. Cody Schuffelen else
106*5c591343SA. Cody Schuffelen value = first;
107*5c591343SA. Cody Schuffelen // Make sure that the size defined something within the current context
108*5c591343SA. Cody Schuffelen CHECK_SIZE(ctx, value);
109*5c591343SA. Cody Schuffelen return value;
110*5c591343SA. Cody Schuffelen Error:
111*5c591343SA. Cody Schuffelen ctx->size = -1; // Makes everything fail from now on.
112*5c591343SA. Cody Schuffelen return -1;
113*5c591343SA. Cody Schuffelen }
114*5c591343SA. Cody Schuffelen
115*5c591343SA. Cody Schuffelen //***ASN1NextTag()
116*5c591343SA. Cody Schuffelen // This function extracts the next type from 'buffer' starting at 'offset'.
117*5c591343SA. Cody Schuffelen // It advances 'offset' as it parses the type and the length of the type. It returns
118*5c591343SA. Cody Schuffelen // the length of the type. On return, the 'length' octets starting at 'offset' are the
119*5c591343SA. Cody Schuffelen // octets of the type.
120*5c591343SA. Cody Schuffelen // Return Type: UINT
121*5c591343SA. Cody Schuffelen // >=0 the number of octets in 'type'
122*5c591343SA. Cody Schuffelen // <0 an error
123*5c591343SA. Cody Schuffelen INT16
ASN1NextTag(ASN1UnmarshalContext * ctx)124*5c591343SA. Cody Schuffelen ASN1NextTag(
125*5c591343SA. Cody Schuffelen ASN1UnmarshalContext *ctx
126*5c591343SA. Cody Schuffelen )
127*5c591343SA. Cody Schuffelen {
128*5c591343SA. Cody Schuffelen // A tag to get?
129*5c591343SA. Cody Schuffelen VERIFY(ctx->offset < ctx->size);
130*5c591343SA. Cody Schuffelen // Get it
131*5c591343SA. Cody Schuffelen ctx->tag = NEXT_OCTET(ctx);
132*5c591343SA. Cody Schuffelen // Make sure that it is not an extended tag
133*5c591343SA. Cody Schuffelen VERIFY((ctx->tag & 0x1F) != 0x1F);
134*5c591343SA. Cody Schuffelen // Get the length field and return that
135*5c591343SA. Cody Schuffelen return ASN1DecodeLength(ctx);
136*5c591343SA. Cody Schuffelen
137*5c591343SA. Cody Schuffelen Error:
138*5c591343SA. Cody Schuffelen // Attempt to read beyond the end of the context or an illegal tag
139*5c591343SA. Cody Schuffelen ctx->size = -1; // Persistent failure
140*5c591343SA. Cody Schuffelen ctx->tag = 0xFF;
141*5c591343SA. Cody Schuffelen return -1;
142*5c591343SA. Cody Schuffelen }
143*5c591343SA. Cody Schuffelen
144*5c591343SA. Cody Schuffelen
145*5c591343SA. Cody Schuffelen //*** ASN1GetBitStringValue()
146*5c591343SA. Cody Schuffelen // Try to parse a bit string of up to 32 bits from a value that is expected to be
147*5c591343SA. Cody Schuffelen // a bit string. The bit string is left justified so that the MSb of the input is
148*5c591343SA. Cody Schuffelen // the MSb of the returned value.
149*5c591343SA. Cody Schuffelen // If there is a general parsing error, the context->size is set to -1.
150*5c591343SA. Cody Schuffelen // Return Type: BOOL
151*5c591343SA. Cody Schuffelen // TRUE(1) success
152*5c591343SA. Cody Schuffelen // FALSE(0) failure
153*5c591343SA. Cody Schuffelen BOOL
ASN1GetBitStringValue(ASN1UnmarshalContext * ctx,UINT32 * val)154*5c591343SA. Cody Schuffelen ASN1GetBitStringValue(
155*5c591343SA. Cody Schuffelen ASN1UnmarshalContext *ctx,
156*5c591343SA. Cody Schuffelen UINT32 *val
157*5c591343SA. Cody Schuffelen )
158*5c591343SA. Cody Schuffelen {
159*5c591343SA. Cody Schuffelen int shift;
160*5c591343SA. Cody Schuffelen INT16 length;
161*5c591343SA. Cody Schuffelen UINT32 value = 0;
162*5c591343SA. Cody Schuffelen int inputBits;
163*5c591343SA. Cody Schuffelen //
164*5c591343SA. Cody Schuffelen length = ASN1NextTag(ctx);
165*5c591343SA. Cody Schuffelen VERIFY(length >= 1);
166*5c591343SA. Cody Schuffelen VERIFY(ctx->tag == ASN1_BITSTRING);
167*5c591343SA. Cody Schuffelen // Get the shift value for the bit field (how many bits to lop off of the end)
168*5c591343SA. Cody Schuffelen shift = NEXT_OCTET(ctx);
169*5c591343SA. Cody Schuffelen length--;
170*5c591343SA. Cody Schuffelen // Get the number of bits in the input
171*5c591343SA. Cody Schuffelen inputBits = (8 * length) - shift;
172*5c591343SA. Cody Schuffelen // the shift count has to make sense
173*5c591343SA. Cody Schuffelen VERIFY((shift < 8) && ((length > 0) || (shift == 0)));
174*5c591343SA. Cody Schuffelen // if there are any bytes left
175*5c591343SA. Cody Schuffelen for(; length > 1; length--)
176*5c591343SA. Cody Schuffelen {
177*5c591343SA. Cody Schuffelen
178*5c591343SA. Cody Schuffelen // for all but the last octet, just shift and add the new octet
179*5c591343SA. Cody Schuffelen VERIFY((value & 0xFF000000) == 0); // can't loose significant bits
180*5c591343SA. Cody Schuffelen value = (value << 8) + NEXT_OCTET(ctx);
181*5c591343SA. Cody Schuffelen
182*5c591343SA. Cody Schuffelen }
183*5c591343SA. Cody Schuffelen if(length == 1)
184*5c591343SA. Cody Schuffelen {
185*5c591343SA. Cody Schuffelen // for the last octet, just shift the accumulated value enough to
186*5c591343SA. Cody Schuffelen // accept the significant bits in the last octet and shift the last
187*5c591343SA. Cody Schuffelen // octet down
188*5c591343SA. Cody Schuffelen VERIFY(((value & (0xFF000000 << (8 - shift)))) == 0);
189*5c591343SA. Cody Schuffelen value = (value << (8 - shift)) + (NEXT_OCTET(ctx) >> shift);
190*5c591343SA. Cody Schuffelen
191*5c591343SA. Cody Schuffelen }
192*5c591343SA. Cody Schuffelen // 'Left justify' the result
193*5c591343SA. Cody Schuffelen if(inputBits > 0)
194*5c591343SA. Cody Schuffelen value <<= (32 - inputBits);
195*5c591343SA. Cody Schuffelen *val = value;
196*5c591343SA. Cody Schuffelen return TRUE;
197*5c591343SA. Cody Schuffelen Error:
198*5c591343SA. Cody Schuffelen ctx->size = -1;
199*5c591343SA. Cody Schuffelen return FALSE;
200*5c591343SA. Cody Schuffelen }
201*5c591343SA. Cody Schuffelen
202*5c591343SA. Cody Schuffelen //*******************************************************************
203*5c591343SA. Cody Schuffelen //** Marshaling Functions
204*5c591343SA. Cody Schuffelen //*******************************************************************
205*5c591343SA. Cody Schuffelen
206*5c591343SA. Cody Schuffelen //*** Introduction
207*5c591343SA. Cody Schuffelen // Marshaling of an ASN.1 structure is accomplished from the bottom up. That is,
208*5c591343SA. Cody Schuffelen // the things that will be at the end of the structure are added last. To manage the
209*5c591343SA. Cody Schuffelen // collecting of the relative sizes, start a context for the outermost container, if
210*5c591343SA. Cody Schuffelen // there is one, and then placing items in from the bottom up. If the bottom-most
211*5c591343SA. Cody Schuffelen // item is also within a structure, create a nested context by calling
212*5c591343SA. Cody Schuffelen // ASN1StartMarshalingContext().
213*5c591343SA. Cody Schuffelen //
214*5c591343SA. Cody Schuffelen // The context control structure contains a 'buffer' pointer, an 'offset', an 'end'
215*5c591343SA. Cody Schuffelen // and a stack. 'offset' is the offset from the start of the buffer of the last added
216*5c591343SA. Cody Schuffelen // byte. When 'offset' reaches 0, the buffer is full. 'offset' is a signed value so
217*5c591343SA. Cody Schuffelen // that, when it becomes negative, there is an overflow. Only two functions are
218*5c591343SA. Cody Schuffelen // allowed to move bytes into the buffer: ASN1PushByte() and ASN1PushBytes(). These
219*5c591343SA. Cody Schuffelen // functions make sure that no data is written beyond the end of the buffer.
220*5c591343SA. Cody Schuffelen //
221*5c591343SA. Cody Schuffelen // When a new context is started, the current value of 'end' is pushed
222*5c591343SA. Cody Schuffelen // on the stack and 'end' is set to 'offset. As bytes are added, offset gets smaller.
223*5c591343SA. Cody Schuffelen // At any time, the count of bytes in the current context is simply 'end' - 'offset'.
224*5c591343SA. Cody Schuffelen //
225*5c591343SA. Cody Schuffelen // Since starting a new context involves setting 'end' = 'offset', the number of bytes
226*5c591343SA. Cody Schuffelen // in the context starts at 0. The nominal way of ending a context is to use
227*5c591343SA. Cody Schuffelen // 'end' - 'offset' to set the length value, and then a tag is added to the buffer.
228*5c591343SA. Cody Schuffelen // Then the previous 'end' value is popped meaning that the context just ended
229*5c591343SA. Cody Schuffelen // becomes a member of the now current context.
230*5c591343SA. Cody Schuffelen //
231*5c591343SA. Cody Schuffelen // The nominal strategy for building a completed ASN.1 structure is to push everything
232*5c591343SA. Cody Schuffelen // into the buffer and then move everything to the start of the buffer. The move is
233*5c591343SA. Cody Schuffelen // simple as the size of the move is the initial 'end' value minus the final 'offset'
234*5c591343SA. Cody Schuffelen // value. The destination is 'buffer' and the source is 'buffer' + 'offset'. As Skippy
235*5c591343SA. Cody Schuffelen // would say "Easy peasy, Joe."
236*5c591343SA. Cody Schuffelen //
237*5c591343SA. Cody Schuffelen // It is not necessary to provide a buffer into which the data is placed. If no buffer
238*5c591343SA. Cody Schuffelen // is provided, then the marshaling process will return values needed for marshaling.
239*5c591343SA. Cody Schuffelen // On strategy for filling the buffer would be to execute the process for building
240*5c591343SA. Cody Schuffelen // the structure without using a buffer. This would return the overall size of the
241*5c591343SA. Cody Schuffelen // structure. Then that amount of data could be allocated for the buffer and the fill
242*5c591343SA. Cody Schuffelen // process executed again with the data going into the buffer. At the end, the data
243*5c591343SA. Cody Schuffelen // would be in its final resting place.
244*5c591343SA. Cody Schuffelen
245*5c591343SA. Cody Schuffelen //*** ASN1InitialializeMarshalContext()
246*5c591343SA. Cody Schuffelen // This creates a structure for handling marshaling of an ASN.1 formatted data
247*5c591343SA. Cody Schuffelen // structure.
248*5c591343SA. Cody Schuffelen void
ASN1InitialializeMarshalContext(ASN1MarshalContext * ctx,INT16 length,BYTE * buffer)249*5c591343SA. Cody Schuffelen ASN1InitialializeMarshalContext(
250*5c591343SA. Cody Schuffelen ASN1MarshalContext *ctx,
251*5c591343SA. Cody Schuffelen INT16 length,
252*5c591343SA. Cody Schuffelen BYTE *buffer
253*5c591343SA. Cody Schuffelen )
254*5c591343SA. Cody Schuffelen {
255*5c591343SA. Cody Schuffelen ctx->buffer = buffer;
256*5c591343SA. Cody Schuffelen if(buffer)
257*5c591343SA. Cody Schuffelen ctx->offset = length;
258*5c591343SA. Cody Schuffelen else
259*5c591343SA. Cody Schuffelen ctx->offset = INT16_MAX;
260*5c591343SA. Cody Schuffelen ctx->end = ctx->offset;
261*5c591343SA. Cody Schuffelen ctx->depth = -1;
262*5c591343SA. Cody Schuffelen }
263*5c591343SA. Cody Schuffelen
264*5c591343SA. Cody Schuffelen //*** ASN1StartMarshalContext()
265*5c591343SA. Cody Schuffelen // This starts a new constructed element. It is constructed on 'top' of the value
266*5c591343SA. Cody Schuffelen // that was previously placed in the structure.
267*5c591343SA. Cody Schuffelen void
ASN1StartMarshalContext(ASN1MarshalContext * ctx)268*5c591343SA. Cody Schuffelen ASN1StartMarshalContext(
269*5c591343SA. Cody Schuffelen ASN1MarshalContext *ctx
270*5c591343SA. Cody Schuffelen )
271*5c591343SA. Cody Schuffelen {
272*5c591343SA. Cody Schuffelen pAssert((ctx->depth + 1) < MAX_DEPTH);
273*5c591343SA. Cody Schuffelen ctx->depth++;
274*5c591343SA. Cody Schuffelen ctx->ends[ctx->depth] = ctx->end;
275*5c591343SA. Cody Schuffelen ctx->end = ctx->offset;
276*5c591343SA. Cody Schuffelen }
277*5c591343SA. Cody Schuffelen
278*5c591343SA. Cody Schuffelen //*** ASN1EndMarshalContext()
279*5c591343SA. Cody Schuffelen // This function restores the end pointer for an encapsulating structure.
280*5c591343SA. Cody Schuffelen // Return Type: INT16
281*5c591343SA. Cody Schuffelen // > 0 the size of the encapsulated structure that was just ended
282*5c591343SA. Cody Schuffelen // <= 0 an error
283*5c591343SA. Cody Schuffelen INT16
ASN1EndMarshalContext(ASN1MarshalContext * ctx)284*5c591343SA. Cody Schuffelen ASN1EndMarshalContext(
285*5c591343SA. Cody Schuffelen ASN1MarshalContext *ctx
286*5c591343SA. Cody Schuffelen )
287*5c591343SA. Cody Schuffelen {
288*5c591343SA. Cody Schuffelen INT16 length;
289*5c591343SA. Cody Schuffelen pAssert(ctx->depth >= 0);
290*5c591343SA. Cody Schuffelen length = ctx->end - ctx->offset;
291*5c591343SA. Cody Schuffelen ctx->end = ctx->ends[ctx->depth--];
292*5c591343SA. Cody Schuffelen if((ctx->depth == -1) && (ctx->buffer))
293*5c591343SA. Cody Schuffelen {
294*5c591343SA. Cody Schuffelen MemoryCopy(ctx->buffer, ctx->buffer + ctx->offset, ctx->end - ctx->offset);
295*5c591343SA. Cody Schuffelen }
296*5c591343SA. Cody Schuffelen return length;
297*5c591343SA. Cody Schuffelen }
298*5c591343SA. Cody Schuffelen
299*5c591343SA. Cody Schuffelen
300*5c591343SA. Cody Schuffelen //***ASN1EndEncapsulation()
301*5c591343SA. Cody Schuffelen // This function puts a tag and length in the buffer. In this function, an embedded
302*5c591343SA. Cody Schuffelen // BIT_STRING is assumed to be a collection of octets. To indicate that all bits
303*5c591343SA. Cody Schuffelen // are used, a byte of zero is prepended. If a raw bit-string is needed, a new
304*5c591343SA. Cody Schuffelen // function like ASN1PushInteger() would be needed.
305*5c591343SA. Cody Schuffelen // Return Type: INT16
306*5c591343SA. Cody Schuffelen // > 0 number of octets in the encapsulation
307*5c591343SA. Cody Schuffelen // == 0 failure
308*5c591343SA. Cody Schuffelen UINT16
ASN1EndEncapsulation(ASN1MarshalContext * ctx,BYTE tag)309*5c591343SA. Cody Schuffelen ASN1EndEncapsulation(
310*5c591343SA. Cody Schuffelen ASN1MarshalContext *ctx,
311*5c591343SA. Cody Schuffelen BYTE tag
312*5c591343SA. Cody Schuffelen )
313*5c591343SA. Cody Schuffelen {
314*5c591343SA. Cody Schuffelen // only add a leading zero for an encapsulated BIT STRING
315*5c591343SA. Cody Schuffelen if (tag == ASN1_BITSTRING)
316*5c591343SA. Cody Schuffelen ASN1PushByte(ctx, 0);
317*5c591343SA. Cody Schuffelen ASN1PushTagAndLength(ctx, tag, ctx->end - ctx->offset);
318*5c591343SA. Cody Schuffelen return ASN1EndMarshalContext(ctx);
319*5c591343SA. Cody Schuffelen }
320*5c591343SA. Cody Schuffelen
321*5c591343SA. Cody Schuffelen //*** ASN1PushByte()
322*5c591343SA. Cody Schuffelen BOOL
ASN1PushByte(ASN1MarshalContext * ctx,BYTE b)323*5c591343SA. Cody Schuffelen ASN1PushByte(
324*5c591343SA. Cody Schuffelen ASN1MarshalContext *ctx,
325*5c591343SA. Cody Schuffelen BYTE b
326*5c591343SA. Cody Schuffelen )
327*5c591343SA. Cody Schuffelen {
328*5c591343SA. Cody Schuffelen if(ctx->offset > 0)
329*5c591343SA. Cody Schuffelen {
330*5c591343SA. Cody Schuffelen ctx->offset -= 1;
331*5c591343SA. Cody Schuffelen if(ctx->buffer)
332*5c591343SA. Cody Schuffelen ctx->buffer[ctx->offset] = b;
333*5c591343SA. Cody Schuffelen return TRUE;
334*5c591343SA. Cody Schuffelen }
335*5c591343SA. Cody Schuffelen ctx->offset = -1;
336*5c591343SA. Cody Schuffelen return FALSE;
337*5c591343SA. Cody Schuffelen }
338*5c591343SA. Cody Schuffelen
339*5c591343SA. Cody Schuffelen //*** ASN1PushBytes()
340*5c591343SA. Cody Schuffelen // Push some raw bytes onto the buffer. 'count' cannot be zero.
341*5c591343SA. Cody Schuffelen // Return Type: IN16
342*5c591343SA. Cody Schuffelen // > 0 count bytes
343*5c591343SA. Cody Schuffelen // == 0 failure unless count was zero
344*5c591343SA. Cody Schuffelen INT16
ASN1PushBytes(ASN1MarshalContext * ctx,INT16 count,const BYTE * buffer)345*5c591343SA. Cody Schuffelen ASN1PushBytes(
346*5c591343SA. Cody Schuffelen ASN1MarshalContext *ctx,
347*5c591343SA. Cody Schuffelen INT16 count,
348*5c591343SA. Cody Schuffelen const BYTE *buffer
349*5c591343SA. Cody Schuffelen )
350*5c591343SA. Cody Schuffelen {
351*5c591343SA. Cody Schuffelen // make sure that count is not negative which would mess up the math; and that
352*5c591343SA. Cody Schuffelen // if there is a count, there is a buffer
353*5c591343SA. Cody Schuffelen VERIFY((count >= 0) && ((buffer != NULL) || (count == 0)));
354*5c591343SA. Cody Schuffelen // back up the offset to determine where the new octets will get pushed
355*5c591343SA. Cody Schuffelen ctx->offset -= count;
356*5c591343SA. Cody Schuffelen // can't go negative
357*5c591343SA. Cody Schuffelen VERIFY(ctx->offset >= 0);
358*5c591343SA. Cody Schuffelen // if there are buffers, move the data, otherwise, assume that this is just a
359*5c591343SA. Cody Schuffelen // test.
360*5c591343SA. Cody Schuffelen if(count && buffer && ctx->buffer)
361*5c591343SA. Cody Schuffelen MemoryCopy(&ctx->buffer[ctx->offset], buffer, count);
362*5c591343SA. Cody Schuffelen return count;
363*5c591343SA. Cody Schuffelen Error:
364*5c591343SA. Cody Schuffelen ctx->offset = -1;
365*5c591343SA. Cody Schuffelen return 0;
366*5c591343SA. Cody Schuffelen }
367*5c591343SA. Cody Schuffelen
368*5c591343SA. Cody Schuffelen //*** ASN1PushNull()
369*5c591343SA. Cody Schuffelen // Return Type: IN16
370*5c591343SA. Cody Schuffelen // > 0 count bytes
371*5c591343SA. Cody Schuffelen // == 0 failure unless count was zero
372*5c591343SA. Cody Schuffelen INT16
ASN1PushNull(ASN1MarshalContext * ctx)373*5c591343SA. Cody Schuffelen ASN1PushNull(
374*5c591343SA. Cody Schuffelen ASN1MarshalContext *ctx
375*5c591343SA. Cody Schuffelen )
376*5c591343SA. Cody Schuffelen {
377*5c591343SA. Cody Schuffelen ASN1PushByte(ctx, 0);
378*5c591343SA. Cody Schuffelen ASN1PushByte(ctx, ASN1_NULL);
379*5c591343SA. Cody Schuffelen return (ctx->offset >= 0) ? 2 : 0;
380*5c591343SA. Cody Schuffelen }
381*5c591343SA. Cody Schuffelen
382*5c591343SA. Cody Schuffelen //*** ASN1PushLength()
383*5c591343SA. Cody Schuffelen // Push a length value. This will only handle length values that fit in an INT16.
384*5c591343SA. Cody Schuffelen // Return Type: UINT16
385*5c591343SA. Cody Schuffelen // > 0 number of bytes added
386*5c591343SA. Cody Schuffelen // == 0 failure
387*5c591343SA. Cody Schuffelen INT16
ASN1PushLength(ASN1MarshalContext * ctx,INT16 len)388*5c591343SA. Cody Schuffelen ASN1PushLength(
389*5c591343SA. Cody Schuffelen ASN1MarshalContext *ctx,
390*5c591343SA. Cody Schuffelen INT16 len
391*5c591343SA. Cody Schuffelen )
392*5c591343SA. Cody Schuffelen {
393*5c591343SA. Cody Schuffelen UINT16 start = ctx->offset;
394*5c591343SA. Cody Schuffelen VERIFY(len >= 0);
395*5c591343SA. Cody Schuffelen if(len <= 127)
396*5c591343SA. Cody Schuffelen ASN1PushByte(ctx, (BYTE)len);
397*5c591343SA. Cody Schuffelen else
398*5c591343SA. Cody Schuffelen {
399*5c591343SA. Cody Schuffelen ASN1PushByte(ctx, (BYTE)(len & 0xFF));
400*5c591343SA. Cody Schuffelen len >>= 8;
401*5c591343SA. Cody Schuffelen if(len == 0)
402*5c591343SA. Cody Schuffelen ASN1PushByte(ctx, 0x81);
403*5c591343SA. Cody Schuffelen else
404*5c591343SA. Cody Schuffelen {
405*5c591343SA. Cody Schuffelen ASN1PushByte(ctx, (BYTE)(len));
406*5c591343SA. Cody Schuffelen ASN1PushByte(ctx, 0x82);
407*5c591343SA. Cody Schuffelen }
408*5c591343SA. Cody Schuffelen }
409*5c591343SA. Cody Schuffelen goto Exit;
410*5c591343SA. Cody Schuffelen Error:
411*5c591343SA. Cody Schuffelen ctx->offset = -1;
412*5c591343SA. Cody Schuffelen Exit:
413*5c591343SA. Cody Schuffelen return (ctx->offset > 0) ? start - ctx->offset : 0;
414*5c591343SA. Cody Schuffelen }
415*5c591343SA. Cody Schuffelen
416*5c591343SA. Cody Schuffelen //*** ASN1PushTagAndLength()
417*5c591343SA. Cody Schuffelen // Return Type: INT16
418*5c591343SA. Cody Schuffelen // > 0 number of bytes added
419*5c591343SA. Cody Schuffelen // == 0 failure
420*5c591343SA. Cody Schuffelen INT16
ASN1PushTagAndLength(ASN1MarshalContext * ctx,BYTE tag,INT16 length)421*5c591343SA. Cody Schuffelen ASN1PushTagAndLength(
422*5c591343SA. Cody Schuffelen ASN1MarshalContext *ctx,
423*5c591343SA. Cody Schuffelen BYTE tag,
424*5c591343SA. Cody Schuffelen INT16 length
425*5c591343SA. Cody Schuffelen )
426*5c591343SA. Cody Schuffelen {
427*5c591343SA. Cody Schuffelen INT16 bytes;
428*5c591343SA. Cody Schuffelen bytes = ASN1PushLength(ctx, length);
429*5c591343SA. Cody Schuffelen bytes += (INT16)ASN1PushByte(ctx, tag);
430*5c591343SA. Cody Schuffelen return (ctx->offset < 0) ? 0 : bytes;
431*5c591343SA. Cody Schuffelen }
432*5c591343SA. Cody Schuffelen
433*5c591343SA. Cody Schuffelen
434*5c591343SA. Cody Schuffelen //*** ASN1PushTaggedOctetString()
435*5c591343SA. Cody Schuffelen // This function will push a random octet string.
436*5c591343SA. Cody Schuffelen // Return Type: INT16
437*5c591343SA. Cody Schuffelen // > 0 number of bytes added
438*5c591343SA. Cody Schuffelen // == 0 failure
439*5c591343SA. Cody Schuffelen INT16
ASN1PushTaggedOctetString(ASN1MarshalContext * ctx,INT16 size,const BYTE * string,BYTE tag)440*5c591343SA. Cody Schuffelen ASN1PushTaggedOctetString(
441*5c591343SA. Cody Schuffelen ASN1MarshalContext *ctx,
442*5c591343SA. Cody Schuffelen INT16 size,
443*5c591343SA. Cody Schuffelen const BYTE *string,
444*5c591343SA. Cody Schuffelen BYTE tag
445*5c591343SA. Cody Schuffelen )
446*5c591343SA. Cody Schuffelen {
447*5c591343SA. Cody Schuffelen ASN1PushBytes(ctx, size, string);
448*5c591343SA. Cody Schuffelen // PushTagAndLenght just tells how many octets it added so the total size of this
449*5c591343SA. Cody Schuffelen // element is the sum of those octets and input size.
450*5c591343SA. Cody Schuffelen size += ASN1PushTagAndLength(ctx, tag, size);
451*5c591343SA. Cody Schuffelen return size;
452*5c591343SA. Cody Schuffelen }
453*5c591343SA. Cody Schuffelen
454*5c591343SA. Cody Schuffelen //*** ASN1PushUINT()
455*5c591343SA. Cody Schuffelen // This function pushes an native-endian integer value. This just changes a
456*5c591343SA. Cody Schuffelen // native-endian integer into a big-endian byte string and calls ASN1PushInteger().
457*5c591343SA. Cody Schuffelen // That function will remove leading zeros and make sure that the number is positive.
458*5c591343SA. Cody Schuffelen // Return Type: IN16
459*5c591343SA. Cody Schuffelen // > 0 count bytes
460*5c591343SA. Cody Schuffelen // == 0 failure unless count was zero
461*5c591343SA. Cody Schuffelen INT16
ASN1PushUINT(ASN1MarshalContext * ctx,UINT32 integer)462*5c591343SA. Cody Schuffelen ASN1PushUINT(
463*5c591343SA. Cody Schuffelen ASN1MarshalContext *ctx,
464*5c591343SA. Cody Schuffelen UINT32 integer
465*5c591343SA. Cody Schuffelen )
466*5c591343SA. Cody Schuffelen {
467*5c591343SA. Cody Schuffelen BYTE marshaled[4];
468*5c591343SA. Cody Schuffelen UINT32_TO_BYTE_ARRAY(integer, marshaled);
469*5c591343SA. Cody Schuffelen return ASN1PushInteger(ctx, 4, marshaled);
470*5c591343SA. Cody Schuffelen }
471*5c591343SA. Cody Schuffelen
472*5c591343SA. Cody Schuffelen //*** ASN1PushInteger
473*5c591343SA. Cody Schuffelen // Push a big-endian integer on the end of the buffer
474*5c591343SA. Cody Schuffelen // Return Type: UINT16
475*5c591343SA. Cody Schuffelen // > 0 the number of bytes marshaled for the integer
476*5c591343SA. Cody Schuffelen // == 0 failure
477*5c591343SA. Cody Schuffelen INT16
ASN1PushInteger(ASN1MarshalContext * ctx,INT16 iLen,BYTE * integer)478*5c591343SA. Cody Schuffelen ASN1PushInteger(
479*5c591343SA. Cody Schuffelen ASN1MarshalContext *ctx, // IN/OUT: buffer context
480*5c591343SA. Cody Schuffelen INT16 iLen, // IN: octets of the integer
481*5c591343SA. Cody Schuffelen BYTE *integer // IN: big-endian integer
482*5c591343SA. Cody Schuffelen )
483*5c591343SA. Cody Schuffelen {
484*5c591343SA. Cody Schuffelen // no leading 0's
485*5c591343SA. Cody Schuffelen while((*integer == 0) && (--iLen > 0))
486*5c591343SA. Cody Schuffelen integer++;
487*5c591343SA. Cody Schuffelen // Move the bytes to the buffer
488*5c591343SA. Cody Schuffelen ASN1PushBytes(ctx, iLen, integer);
489*5c591343SA. Cody Schuffelen // if needed, add a leading byte of 0 to make the number positive
490*5c591343SA. Cody Schuffelen if(*integer & 0x80)
491*5c591343SA. Cody Schuffelen iLen += (INT16)ASN1PushByte(ctx, 0);
492*5c591343SA. Cody Schuffelen // PushTagAndLenght just tells how many octets it added so the total size of this
493*5c591343SA. Cody Schuffelen // element is the sum of those octets and the adjusted input size.
494*5c591343SA. Cody Schuffelen iLen += ASN1PushTagAndLength(ctx, ASN1_INTEGER, iLen);
495*5c591343SA. Cody Schuffelen return iLen;
496*5c591343SA. Cody Schuffelen }
497*5c591343SA. Cody Schuffelen
498*5c591343SA. Cody Schuffelen //*** ASN1PushOID()
499*5c591343SA. Cody Schuffelen // This function is used to add an OID. An OID is 0x06 followed by a byte of size
500*5c591343SA. Cody Schuffelen // followed by size bytes. This is used to avoid having to do anything special in the
501*5c591343SA. Cody Schuffelen // definition of an OID.
502*5c591343SA. Cody Schuffelen // Return Type: UINT16
503*5c591343SA. Cody Schuffelen // > 0 the number of bytes marshaled for the integer
504*5c591343SA. Cody Schuffelen // == 0 failure
505*5c591343SA. Cody Schuffelen INT16
ASN1PushOID(ASN1MarshalContext * ctx,const BYTE * OID)506*5c591343SA. Cody Schuffelen ASN1PushOID(
507*5c591343SA. Cody Schuffelen ASN1MarshalContext *ctx,
508*5c591343SA. Cody Schuffelen const BYTE *OID
509*5c591343SA. Cody Schuffelen )
510*5c591343SA. Cody Schuffelen {
511*5c591343SA. Cody Schuffelen if((*OID == ASN1_OBJECT_IDENTIFIER) && ((OID[1] & 0x80) == 0))
512*5c591343SA. Cody Schuffelen {
513*5c591343SA. Cody Schuffelen return ASN1PushBytes(ctx, OID[1] + 2, OID);
514*5c591343SA. Cody Schuffelen }
515*5c591343SA. Cody Schuffelen ctx->offset = -1;
516*5c591343SA. Cody Schuffelen return 0;
517*5c591343SA. Cody Schuffelen }
518*5c591343SA. Cody Schuffelen
519*5c591343SA. Cody Schuffelen
520