1 /* Microsoft Reference Implementation for TPM 2.0
2 *
3 * The copyright in this software is being made available under the BSD License,
4 * included below. This software may be subject to other third party and
5 * contributor rights, including patent rights, and no such rights are granted
6 * under this license.
7 *
8 * Copyright (c) Microsoft Corporation
9 *
10 * All rights reserved.
11 *
12 * BSD License
13 *
14 * Redistribution and use in source and binary forms, with or without modification,
15 * are permitted provided that the following conditions are met:
16 *
17 * Redistributions of source code must retain the above copyright notice, this list
18 * of conditions and the following disclaimer.
19 *
20 * Redistributions in binary form must reproduce the above copyright notice, this
21 * list of conditions and the following disclaimer in the documentation and/or
22 * other materials provided with the distribution.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS""
25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
28 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
31 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35 //** Introduction
36 // This file contains the basic conversion functions that will convert TPM2B
37 // to/from the internal format. The internal format is a bigNum,
38 //
39
40 //** Includes
41
42 #include "Tpm.h"
43
44 //** Functions
45
46 //*** BnFromBytes()
47 // This function will convert a big-endian byte array to the internal number
48 // format. If bn is NULL, then the output is NULL. If bytes is null or the
49 // required size is 0, then the output is set to zero
50 LIB_EXPORT bigNum
BnFromBytes(bigNum bn,const BYTE * bytes,NUMBYTES nBytes)51 BnFromBytes(
52 bigNum bn,
53 const BYTE *bytes,
54 NUMBYTES nBytes
55 )
56 {
57 const BYTE *pFrom; // 'p' points to the least significant bytes of source
58 BYTE *pTo; // points to least significant bytes of destination
59 crypt_uword_t size;
60 //
61
62 size = (bytes != NULL) ? BYTES_TO_CRYPT_WORDS(nBytes) : 0;
63
64 // If nothing in, nothing out
65 if(bn == NULL)
66 return NULL;
67
68 // make sure things fit
69 pAssert(BnGetAllocated(bn) >= size);
70
71 if(size > 0)
72 {
73 // Clear the topmost word in case it is not filled with data
74 bn->d[size - 1] = 0;
75 // Moving the input bytes from the end of the list (LSB) end
76 pFrom = bytes + nBytes - 1;
77 // To the LS0 of the LSW of the bigNum.
78 pTo = (BYTE *)bn->d;
79 for(; nBytes != 0; nBytes--)
80 *pTo++ = *pFrom--;
81 // For a little-endian machine, the conversion is a straight byte
82 // reversal. For a big-endian machine, we have to put the words in
83 // big-endian byte order
84 #if BIG_ENDIAN_TPM
85 {
86 crypt_word_t t;
87 for(t = (crypt_word_t)size - 1; t >= 0; t--)
88 bn->d[t] = SWAP_CRYPT_WORD(bn->d[t]);
89 }
90 #endif
91 }
92 BnSetTop(bn, size);
93 return bn;
94 }
95
96 //*** BnFrom2B()
97 // Convert an TPM2B to a BIG_NUM.
98 // If the input value does not exist, or the output does not exist, or the input
99 // will not fit into the output the function returns NULL
100 LIB_EXPORT bigNum
BnFrom2B(bigNum bn,const TPM2B * a2B)101 BnFrom2B(
102 bigNum bn, // OUT:
103 const TPM2B *a2B // IN: number to convert
104 )
105 {
106 if(a2B != NULL)
107 return BnFromBytes(bn, a2B->buffer, a2B->size);
108 // Make sure that the number has an initialized value rather than whatever
109 // was there before
110 BnSetTop(bn, 0); // Function accepts NULL
111 return NULL;
112 }
113
114 //*** BnFromHex()
115 // Convert a hex string into a bigNum. This is primarily used in debugging.
116 LIB_EXPORT bigNum
BnFromHex(bigNum bn,const char * hex)117 BnFromHex(
118 bigNum bn, // OUT:
119 const char *hex // IN:
120 )
121 {
122 #define FromHex(a) ((a) - (((a) > 'a') ? ('a' + 10) \
123 : ((a) > 'A') ? ('A' - 10) : '0'))
124 unsigned i;
125 unsigned wordCount;
126 const char *p;
127 BYTE *d = (BYTE *)&(bn->d[0]);
128 //
129 pAssert(bn && hex);
130 i = (unsigned)strlen(hex);
131 wordCount = BYTES_TO_CRYPT_WORDS((i + 1) / 2);
132 if((i == 0) || (wordCount >= BnGetAllocated(bn)))
133 BnSetWord(bn, 0);
134 else
135 {
136 bn->d[wordCount - 1] = 0;
137 p = hex + i - 1;
138 for(;i > 1; i -= 2)
139 {
140 BYTE a;
141 a = FromHex(*p);
142 p--;
143 *d++ = a + (FromHex(*p) << 4);
144 p--;
145 }
146 if(i == 1)
147 *d = FromHex(*p);
148 }
149 #if !BIG_ENDIAN_TPM
150 for(i = 0; i < wordCount; i++)
151 bn->d[i] = SWAP_CRYPT_WORD(bn->d[i]);
152 #endif // BIG_ENDIAN_TPM
153 BnSetTop(bn, wordCount);
154 return bn;
155 }
156
157 //*** BnToBytes()
158 // This function converts a BIG_NUM to a byte array. It converts the bigNum to a
159 // big-endian byte string and sets 'size' to the normalized value. If 'size' is an
160 // input 0, then the receiving buffer is guaranteed to be large enough for the result
161 // and the size will be set to the size required for bigNum (leading zeros
162 // suppressed).
163 //
164 // The conversion for a little-endian machine simply requires that all significant
165 // bytes of the bigNum be reversed. For a big-endian machine, rather than
166 // unpack each word individually, the bigNum is converted to little-endian words,
167 // copied, and then converted back to big-endian.
168 LIB_EXPORT BOOL
BnToBytes(bigConst bn,BYTE * buffer,NUMBYTES * size)169 BnToBytes(
170 bigConst bn,
171 BYTE *buffer,
172 NUMBYTES *size // This the number of bytes that are
173 // available in the buffer. The result
174 // should be this big.
175 )
176 {
177 crypt_uword_t requiredSize;
178 BYTE *pFrom;
179 BYTE *pTo;
180 crypt_uword_t count;
181 //
182 // validate inputs
183 pAssert(bn && buffer && size);
184
185 requiredSize = (BnSizeInBits(bn) + 7) / 8;
186 if(requiredSize == 0)
187 {
188 // If the input value is 0, return a byte of zero
189 *size = 1;
190 *buffer = 0;
191 }
192 else
193 {
194 #if BIG_ENDIAN_TPM
195 // Copy the constant input value into a modifiable value
196 BN_VAR(bnL, LARGEST_NUMBER_BITS * 2);
197 BnCopy(bnL, bn);
198 // byte swap the words in the local value to make them little-endian
199 for(count = 0; count < bnL->size; count++)
200 bnL->d[count] = SWAP_CRYPT_WORD(bnL->d[count]);
201 bn = (bigConst)bnL;
202 #endif
203 if(*size == 0)
204 *size = (NUMBYTES)requiredSize;
205 pAssert(requiredSize <= *size);
206 // Byte swap the number (not words but the whole value)
207 count = *size;
208 // Start from the least significant word and offset to the most significant
209 // byte which is in some high word
210 pFrom = (BYTE *)(&bn->d[0]) + requiredSize - 1;
211 pTo = buffer;
212
213 // If the number of output bytes is larger than the number bytes required
214 // for the input number, pad with zeros
215 for(count = *size; count > requiredSize; count--)
216 *pTo++ = 0;
217 // Move the most significant byte at the end of the BigNum to the next most
218 // significant byte position of the 2B and repeat for all significant bytes.
219 for(; requiredSize > 0; requiredSize--)
220 *pTo++ = *pFrom--;
221 }
222 return TRUE;
223 }
224
225 //*** BnTo2B()
226 // Function to convert a BIG_NUM to TPM2B.
227 // The TPM2B size is set to the requested 'size' which may require padding.
228 // If 'size' is non-zero and less than required by the value in 'bn' then an error
229 // is returned. If 'size' is zero, then the TPM2B is assumed to be large enough
230 // for the data and a2b->size will be adjusted accordingly.
231 LIB_EXPORT BOOL
BnTo2B(bigConst bn,TPM2B * a2B,NUMBYTES size)232 BnTo2B(
233 bigConst bn, // IN:
234 TPM2B *a2B, // OUT:
235 NUMBYTES size // IN: the desired size
236 )
237 {
238 // Set the output size
239 if(bn && a2B)
240 {
241 a2B->size = size;
242 return BnToBytes(bn, a2B->buffer, &a2B->size);
243 }
244 return FALSE;
245 }
246
247 #if ALG_ECC
248
249 //*** BnPointFrom2B()
250 // Function to create a BIG_POINT structure from a 2B point.
251 // A point is going to be two ECC values in the same buffer. The values are going
252 // to be the size of the modulus. They are in modular form.
253 LIB_EXPORT bn_point_t *
BnPointFrom2B(bigPoint ecP,TPMS_ECC_POINT * p)254 BnPointFrom2B(
255 bigPoint ecP, // OUT: the preallocated point structure
256 TPMS_ECC_POINT *p // IN: the number to convert
257 )
258 {
259 if(p == NULL)
260 return NULL;
261
262 if(NULL != ecP)
263 {
264 BnFrom2B(ecP->x, &p->x.b);
265 BnFrom2B(ecP->y, &p->y.b);
266 BnSetWord(ecP->z, 1);
267 }
268 return ecP;
269 }
270
271 //*** BnPointTo2B()
272 // This function converts a BIG_POINT into a TPMS_ECC_POINT. A TPMS_ECC_POINT
273 // contains two TPM2B_ECC_PARAMETER values. The maximum size of the parameters
274 // is dependent on the maximum EC key size used in an implementation.
275 // The presumption is that the TPMS_ECC_POINT is large enough to hold 2 TPM2B
276 // values, each as large as a MAX_ECC_PARAMETER_BYTES
277 LIB_EXPORT BOOL
BnPointTo2B(TPMS_ECC_POINT * p,bigPoint ecP,bigCurve E)278 BnPointTo2B(
279 TPMS_ECC_POINT *p, // OUT: the converted 2B structure
280 bigPoint ecP, // IN: the values to be converted
281 bigCurve E // IN: curve descriptor for the point
282 )
283 {
284 UINT16 size;
285 //
286 pAssert(p && ecP && E);
287 pAssert(BnEqualWord(ecP->z, 1));
288 // BnMsb is the bit number of the MSB. This is one less than the number of bits
289 size = (UINT16)BITS_TO_BYTES(BnSizeInBits(CurveGetOrder(AccessCurveData(E))));
290 BnTo2B(ecP->x, &p->x.b, size);
291 BnTo2B(ecP->y, &p->y.b, size);
292 return TRUE;
293 }
294
295 #endif // ALG_ECC