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 and Defines
36*5c591343SA. Cody Schuffelen #include "Tpm.h"
37*5c591343SA. Cody Schuffelen
38*5c591343SA. Cody Schuffelen #if ALG_ECC
39*5c591343SA. Cody Schuffelen
40*5c591343SA. Cody Schuffelen // This version requires that the new format for ECC data be used
41*5c591343SA. Cody Schuffelen #if !USE_BN_ECC_DATA
42*5c591343SA. Cody Schuffelen #error "Need to SET USE_BN_ECC_DATA to YES in Implementaion.h"
43*5c591343SA. Cody Schuffelen #endif
44*5c591343SA. Cody Schuffelen
45*5c591343SA. Cody Schuffelen //** Functions
46*5c591343SA. Cody Schuffelen
47*5c591343SA. Cody Schuffelen #if SIMULATION
48*5c591343SA. Cody Schuffelen void
EccSimulationEnd(void)49*5c591343SA. Cody Schuffelen EccSimulationEnd(
50*5c591343SA. Cody Schuffelen void
51*5c591343SA. Cody Schuffelen )
52*5c591343SA. Cody Schuffelen {
53*5c591343SA. Cody Schuffelen #if SIMULATION
54*5c591343SA. Cody Schuffelen // put things to be printed at the end of the simulation here
55*5c591343SA. Cody Schuffelen #endif
56*5c591343SA. Cody Schuffelen }
57*5c591343SA. Cody Schuffelen #endif // SIMULATION
58*5c591343SA. Cody Schuffelen
59*5c591343SA. Cody Schuffelen //*** CryptEccInit()
60*5c591343SA. Cody Schuffelen // This function is called at _TPM_Init
61*5c591343SA. Cody Schuffelen BOOL
CryptEccInit(void)62*5c591343SA. Cody Schuffelen CryptEccInit(
63*5c591343SA. Cody Schuffelen void
64*5c591343SA. Cody Schuffelen )
65*5c591343SA. Cody Schuffelen {
66*5c591343SA. Cody Schuffelen return TRUE;
67*5c591343SA. Cody Schuffelen }
68*5c591343SA. Cody Schuffelen
69*5c591343SA. Cody Schuffelen //*** CryptEccStartup()
70*5c591343SA. Cody Schuffelen // This function is called at TPM2_Startup().
71*5c591343SA. Cody Schuffelen BOOL
CryptEccStartup(void)72*5c591343SA. Cody Schuffelen CryptEccStartup(
73*5c591343SA. Cody Schuffelen void
74*5c591343SA. Cody Schuffelen )
75*5c591343SA. Cody Schuffelen {
76*5c591343SA. Cody Schuffelen return TRUE;
77*5c591343SA. Cody Schuffelen }
78*5c591343SA. Cody Schuffelen
79*5c591343SA. Cody Schuffelen //*** ClearPoint2B(generic)
80*5c591343SA. Cody Schuffelen // Initialize the size values of a TPMS_ECC_POINT structure.
81*5c591343SA. Cody Schuffelen void
ClearPoint2B(TPMS_ECC_POINT * p)82*5c591343SA. Cody Schuffelen ClearPoint2B(
83*5c591343SA. Cody Schuffelen TPMS_ECC_POINT *p // IN: the point
84*5c591343SA. Cody Schuffelen )
85*5c591343SA. Cody Schuffelen {
86*5c591343SA. Cody Schuffelen if(p != NULL)
87*5c591343SA. Cody Schuffelen {
88*5c591343SA. Cody Schuffelen p->x.t.size = 0;
89*5c591343SA. Cody Schuffelen p->y.t.size = 0;
90*5c591343SA. Cody Schuffelen }
91*5c591343SA. Cody Schuffelen }
92*5c591343SA. Cody Schuffelen
93*5c591343SA. Cody Schuffelen //*** CryptEccGetParametersByCurveId()
94*5c591343SA. Cody Schuffelen // This function returns a pointer to the curve data that is associated with
95*5c591343SA. Cody Schuffelen // the indicated curveId.
96*5c591343SA. Cody Schuffelen // If there is no curve with the indicated ID, the function returns NULL. This
97*5c591343SA. Cody Schuffelen // function is in this module so that it can be called by GetCurve data.
98*5c591343SA. Cody Schuffelen // Return Type: const ECC_CURVE_DATA
99*5c591343SA. Cody Schuffelen // NULL curve with the indicated TPM_ECC_CURVE is not implemented
100*5c591343SA. Cody Schuffelen // != NULL pointer to the curve data
101*5c591343SA. Cody Schuffelen LIB_EXPORT const ECC_CURVE *
CryptEccGetParametersByCurveId(TPM_ECC_CURVE curveId)102*5c591343SA. Cody Schuffelen CryptEccGetParametersByCurveId(
103*5c591343SA. Cody Schuffelen TPM_ECC_CURVE curveId // IN: the curveID
104*5c591343SA. Cody Schuffelen )
105*5c591343SA. Cody Schuffelen {
106*5c591343SA. Cody Schuffelen int i;
107*5c591343SA. Cody Schuffelen for(i = 0; i < ECC_CURVE_COUNT; i++)
108*5c591343SA. Cody Schuffelen {
109*5c591343SA. Cody Schuffelen if(eccCurves[i].curveId == curveId)
110*5c591343SA. Cody Schuffelen return &eccCurves[i];
111*5c591343SA. Cody Schuffelen }
112*5c591343SA. Cody Schuffelen return NULL;
113*5c591343SA. Cody Schuffelen }
114*5c591343SA. Cody Schuffelen
115*5c591343SA. Cody Schuffelen //*** CryptEccGetKeySizeForCurve()
116*5c591343SA. Cody Schuffelen // This function returns the key size in bits of the indicated curve.
117*5c591343SA. Cody Schuffelen LIB_EXPORT UINT16
CryptEccGetKeySizeForCurve(TPM_ECC_CURVE curveId)118*5c591343SA. Cody Schuffelen CryptEccGetKeySizeForCurve(
119*5c591343SA. Cody Schuffelen TPM_ECC_CURVE curveId // IN: the curve
120*5c591343SA. Cody Schuffelen )
121*5c591343SA. Cody Schuffelen {
122*5c591343SA. Cody Schuffelen const ECC_CURVE *curve = CryptEccGetParametersByCurveId(curveId);
123*5c591343SA. Cody Schuffelen UINT16 keySizeInBits;
124*5c591343SA. Cody Schuffelen //
125*5c591343SA. Cody Schuffelen keySizeInBits = (curve != NULL) ? curve->keySizeBits : 0;
126*5c591343SA. Cody Schuffelen return keySizeInBits;
127*5c591343SA. Cody Schuffelen }
128*5c591343SA. Cody Schuffelen
129*5c591343SA. Cody Schuffelen //*** GetCurveData()
130*5c591343SA. Cody Schuffelen // This function returns the a pointer for the parameter data
131*5c591343SA. Cody Schuffelen // associated with a curve.
132*5c591343SA. Cody Schuffelen const ECC_CURVE_DATA *
GetCurveData(TPM_ECC_CURVE curveId)133*5c591343SA. Cody Schuffelen GetCurveData(
134*5c591343SA. Cody Schuffelen TPM_ECC_CURVE curveId // IN: the curveID
135*5c591343SA. Cody Schuffelen )
136*5c591343SA. Cody Schuffelen {
137*5c591343SA. Cody Schuffelen const ECC_CURVE *curve = CryptEccGetParametersByCurveId(curveId);
138*5c591343SA. Cody Schuffelen return (curve != NULL) ? curve->curveData : NULL;
139*5c591343SA. Cody Schuffelen }
140*5c591343SA. Cody Schuffelen
141*5c591343SA. Cody Schuffelen //***CryptEccGetOID()
142*5c591343SA. Cody Schuffelen const BYTE *
CryptEccGetOID(TPM_ECC_CURVE curveId)143*5c591343SA. Cody Schuffelen CryptEccGetOID(
144*5c591343SA. Cody Schuffelen TPM_ECC_CURVE curveId
145*5c591343SA. Cody Schuffelen )
146*5c591343SA. Cody Schuffelen {
147*5c591343SA. Cody Schuffelen const ECC_CURVE *curve = CryptEccGetParametersByCurveId(curveId);
148*5c591343SA. Cody Schuffelen return (curve != NULL) ? curve->OID : NULL;
149*5c591343SA. Cody Schuffelen }
150*5c591343SA. Cody Schuffelen
151*5c591343SA. Cody Schuffelen //*** CryptEccGetCurveByIndex()
152*5c591343SA. Cody Schuffelen // This function returns the number of the 'i'-th implemented curve. The normal
153*5c591343SA. Cody Schuffelen // use would be to call this function with 'i' starting at 0. When the 'i' is greater
154*5c591343SA. Cody Schuffelen // than or equal to the number of implemented curves, TPM_ECC_NONE is returned.
155*5c591343SA. Cody Schuffelen LIB_EXPORT TPM_ECC_CURVE
CryptEccGetCurveByIndex(UINT16 i)156*5c591343SA. Cody Schuffelen CryptEccGetCurveByIndex(
157*5c591343SA. Cody Schuffelen UINT16 i
158*5c591343SA. Cody Schuffelen )
159*5c591343SA. Cody Schuffelen {
160*5c591343SA. Cody Schuffelen if(i >= ECC_CURVE_COUNT)
161*5c591343SA. Cody Schuffelen return TPM_ECC_NONE;
162*5c591343SA. Cody Schuffelen return eccCurves[i].curveId;
163*5c591343SA. Cody Schuffelen }
164*5c591343SA. Cody Schuffelen
165*5c591343SA. Cody Schuffelen //*** CryptEccGetParameter()
166*5c591343SA. Cody Schuffelen // This function returns an ECC curve parameter. The parameter is
167*5c591343SA. Cody Schuffelen // selected by a single character designator from the set of ""PNABXYH"".
168*5c591343SA. Cody Schuffelen // Return Type: BOOL
169*5c591343SA. Cody Schuffelen // TRUE(1) curve exists and parameter returned
170*5c591343SA. Cody Schuffelen // FALSE(0) curve does not exist or parameter selector
171*5c591343SA. Cody Schuffelen LIB_EXPORT BOOL
CryptEccGetParameter(TPM2B_ECC_PARAMETER * out,char p,TPM_ECC_CURVE curveId)172*5c591343SA. Cody Schuffelen CryptEccGetParameter(
173*5c591343SA. Cody Schuffelen TPM2B_ECC_PARAMETER *out, // OUT: place to put parameter
174*5c591343SA. Cody Schuffelen char p, // IN: the parameter selector
175*5c591343SA. Cody Schuffelen TPM_ECC_CURVE curveId // IN: the curve id
176*5c591343SA. Cody Schuffelen )
177*5c591343SA. Cody Schuffelen {
178*5c591343SA. Cody Schuffelen const ECC_CURVE_DATA *curve = GetCurveData(curveId);
179*5c591343SA. Cody Schuffelen bigConst parameter = NULL;
180*5c591343SA. Cody Schuffelen
181*5c591343SA. Cody Schuffelen if(curve != NULL)
182*5c591343SA. Cody Schuffelen {
183*5c591343SA. Cody Schuffelen switch(p)
184*5c591343SA. Cody Schuffelen {
185*5c591343SA. Cody Schuffelen case 'p':
186*5c591343SA. Cody Schuffelen parameter = CurveGetPrime(curve);
187*5c591343SA. Cody Schuffelen break;
188*5c591343SA. Cody Schuffelen case 'n':
189*5c591343SA. Cody Schuffelen parameter = CurveGetOrder(curve);
190*5c591343SA. Cody Schuffelen break;
191*5c591343SA. Cody Schuffelen case 'a':
192*5c591343SA. Cody Schuffelen parameter = CurveGet_a(curve);
193*5c591343SA. Cody Schuffelen break;
194*5c591343SA. Cody Schuffelen case 'b':
195*5c591343SA. Cody Schuffelen parameter = CurveGet_b(curve);
196*5c591343SA. Cody Schuffelen break;
197*5c591343SA. Cody Schuffelen case 'x':
198*5c591343SA. Cody Schuffelen parameter = CurveGetGx(curve);
199*5c591343SA. Cody Schuffelen break;
200*5c591343SA. Cody Schuffelen case 'y':
201*5c591343SA. Cody Schuffelen parameter = CurveGetGy(curve);
202*5c591343SA. Cody Schuffelen break;
203*5c591343SA. Cody Schuffelen case 'h':
204*5c591343SA. Cody Schuffelen parameter = CurveGetCofactor(curve);
205*5c591343SA. Cody Schuffelen break;
206*5c591343SA. Cody Schuffelen default:
207*5c591343SA. Cody Schuffelen FAIL(FATAL_ERROR_INTERNAL);
208*5c591343SA. Cody Schuffelen break;
209*5c591343SA. Cody Schuffelen }
210*5c591343SA. Cody Schuffelen }
211*5c591343SA. Cody Schuffelen // If not debugging and we get here with parameter still NULL, had better
212*5c591343SA. Cody Schuffelen // not try to convert so just return FALSE instead.
213*5c591343SA. Cody Schuffelen return (parameter != NULL) ? BnTo2B(parameter, &out->b, 0) : 0;
214*5c591343SA. Cody Schuffelen }
215*5c591343SA. Cody Schuffelen
216*5c591343SA. Cody Schuffelen //*** CryptCapGetECCCurve()
217*5c591343SA. Cody Schuffelen // This function returns the list of implemented ECC curves.
218*5c591343SA. Cody Schuffelen // Return Type: TPMI_YES_NO
219*5c591343SA. Cody Schuffelen // YES if no more ECC curve is available
220*5c591343SA. Cody Schuffelen // NO if there are more ECC curves not reported
221*5c591343SA. Cody Schuffelen TPMI_YES_NO
CryptCapGetECCCurve(TPM_ECC_CURVE curveID,UINT32 maxCount,TPML_ECC_CURVE * curveList)222*5c591343SA. Cody Schuffelen CryptCapGetECCCurve(
223*5c591343SA. Cody Schuffelen TPM_ECC_CURVE curveID, // IN: the starting ECC curve
224*5c591343SA. Cody Schuffelen UINT32 maxCount, // IN: count of returned curves
225*5c591343SA. Cody Schuffelen TPML_ECC_CURVE *curveList // OUT: ECC curve list
226*5c591343SA. Cody Schuffelen )
227*5c591343SA. Cody Schuffelen {
228*5c591343SA. Cody Schuffelen TPMI_YES_NO more = NO;
229*5c591343SA. Cody Schuffelen UINT16 i;
230*5c591343SA. Cody Schuffelen UINT32 count = ECC_CURVE_COUNT;
231*5c591343SA. Cody Schuffelen TPM_ECC_CURVE curve;
232*5c591343SA. Cody Schuffelen
233*5c591343SA. Cody Schuffelen // Initialize output property list
234*5c591343SA. Cody Schuffelen curveList->count = 0;
235*5c591343SA. Cody Schuffelen
236*5c591343SA. Cody Schuffelen // The maximum count of curves we may return is MAX_ECC_CURVES
237*5c591343SA. Cody Schuffelen if(maxCount > MAX_ECC_CURVES) maxCount = MAX_ECC_CURVES;
238*5c591343SA. Cody Schuffelen
239*5c591343SA. Cody Schuffelen // Scan the eccCurveValues array
240*5c591343SA. Cody Schuffelen for(i = 0; i < count; i++)
241*5c591343SA. Cody Schuffelen {
242*5c591343SA. Cody Schuffelen curve = CryptEccGetCurveByIndex(i);
243*5c591343SA. Cody Schuffelen // If curveID is less than the starting curveID, skip it
244*5c591343SA. Cody Schuffelen if(curve < curveID)
245*5c591343SA. Cody Schuffelen continue;
246*5c591343SA. Cody Schuffelen if(curveList->count < maxCount)
247*5c591343SA. Cody Schuffelen {
248*5c591343SA. Cody Schuffelen // If we have not filled up the return list, add more curves to
249*5c591343SA. Cody Schuffelen // it
250*5c591343SA. Cody Schuffelen curveList->eccCurves[curveList->count] = curve;
251*5c591343SA. Cody Schuffelen curveList->count++;
252*5c591343SA. Cody Schuffelen }
253*5c591343SA. Cody Schuffelen else
254*5c591343SA. Cody Schuffelen {
255*5c591343SA. Cody Schuffelen // If the return list is full but we still have curves
256*5c591343SA. Cody Schuffelen // available, report this and stop iterating
257*5c591343SA. Cody Schuffelen more = YES;
258*5c591343SA. Cody Schuffelen break;
259*5c591343SA. Cody Schuffelen }
260*5c591343SA. Cody Schuffelen }
261*5c591343SA. Cody Schuffelen return more;
262*5c591343SA. Cody Schuffelen }
263*5c591343SA. Cody Schuffelen
264*5c591343SA. Cody Schuffelen //*** CryptGetCurveSignScheme()
265*5c591343SA. Cody Schuffelen // This function will return a pointer to the scheme of the curve.
266*5c591343SA. Cody Schuffelen const TPMT_ECC_SCHEME *
CryptGetCurveSignScheme(TPM_ECC_CURVE curveId)267*5c591343SA. Cody Schuffelen CryptGetCurveSignScheme(
268*5c591343SA. Cody Schuffelen TPM_ECC_CURVE curveId // IN: The curve selector
269*5c591343SA. Cody Schuffelen )
270*5c591343SA. Cody Schuffelen {
271*5c591343SA. Cody Schuffelen const ECC_CURVE *curve = CryptEccGetParametersByCurveId(curveId);
272*5c591343SA. Cody Schuffelen
273*5c591343SA. Cody Schuffelen if(curve != NULL)
274*5c591343SA. Cody Schuffelen return &(curve->sign);
275*5c591343SA. Cody Schuffelen else
276*5c591343SA. Cody Schuffelen return NULL;
277*5c591343SA. Cody Schuffelen }
278*5c591343SA. Cody Schuffelen
279*5c591343SA. Cody Schuffelen //*** CryptGenerateR()
280*5c591343SA. Cody Schuffelen // This function computes the commit random value for a split signing scheme.
281*5c591343SA. Cody Schuffelen //
282*5c591343SA. Cody Schuffelen // If 'c' is NULL, it indicates that 'r' is being generated
283*5c591343SA. Cody Schuffelen // for TPM2_Commit.
284*5c591343SA. Cody Schuffelen // If 'c' is not NULL, the TPM will validate that the 'gr.commitArray'
285*5c591343SA. Cody Schuffelen // bit associated with the input value of 'c' is SET. If not, the TPM
286*5c591343SA. Cody Schuffelen // returns FALSE and no 'r' value is generated.
287*5c591343SA. Cody Schuffelen // Return Type: BOOL
288*5c591343SA. Cody Schuffelen // TRUE(1) r value computed
289*5c591343SA. Cody Schuffelen // FALSE(0) no r value computed
290*5c591343SA. Cody Schuffelen BOOL
CryptGenerateR(TPM2B_ECC_PARAMETER * r,UINT16 * c,TPMI_ECC_CURVE curveID,TPM2B_NAME * name)291*5c591343SA. Cody Schuffelen CryptGenerateR(
292*5c591343SA. Cody Schuffelen TPM2B_ECC_PARAMETER *r, // OUT: the generated random value
293*5c591343SA. Cody Schuffelen UINT16 *c, // IN/OUT: count value.
294*5c591343SA. Cody Schuffelen TPMI_ECC_CURVE curveID, // IN: the curve for the value
295*5c591343SA. Cody Schuffelen TPM2B_NAME *name // IN: optional name of a key to
296*5c591343SA. Cody Schuffelen // associate with 'r'
297*5c591343SA. Cody Schuffelen )
298*5c591343SA. Cody Schuffelen {
299*5c591343SA. Cody Schuffelen // This holds the marshaled g_commitCounter.
300*5c591343SA. Cody Schuffelen TPM2B_TYPE(8B, 8);
301*5c591343SA. Cody Schuffelen TPM2B_8B cntr = {{8,{0}}};
302*5c591343SA. Cody Schuffelen UINT32 iterations;
303*5c591343SA. Cody Schuffelen TPM2B_ECC_PARAMETER n;
304*5c591343SA. Cody Schuffelen UINT64 currentCount = gr.commitCounter;
305*5c591343SA. Cody Schuffelen UINT16 t1;
306*5c591343SA. Cody Schuffelen //
307*5c591343SA. Cody Schuffelen if(!CryptEccGetParameter(&n, 'n', curveID))
308*5c591343SA. Cody Schuffelen return FALSE;
309*5c591343SA. Cody Schuffelen
310*5c591343SA. Cody Schuffelen // If this is the commit phase, use the current value of the commit counter
311*5c591343SA. Cody Schuffelen if(c != NULL)
312*5c591343SA. Cody Schuffelen {
313*5c591343SA. Cody Schuffelen // if the array bit is not set, can't use the value.
314*5c591343SA. Cody Schuffelen if(!TEST_BIT((*c & COMMIT_INDEX_MASK), gr.commitArray))
315*5c591343SA. Cody Schuffelen return FALSE;
316*5c591343SA. Cody Schuffelen
317*5c591343SA. Cody Schuffelen // If it is the sign phase, figure out what the counter value was
318*5c591343SA. Cody Schuffelen // when the commitment was made.
319*5c591343SA. Cody Schuffelen //
320*5c591343SA. Cody Schuffelen // When gr.commitArray has less than 64K bits, the extra
321*5c591343SA. Cody Schuffelen // bits of 'c' are used as a check to make sure that the
322*5c591343SA. Cody Schuffelen // signing operation is not using an out of range count value
323*5c591343SA. Cody Schuffelen t1 = (UINT16)currentCount;
324*5c591343SA. Cody Schuffelen
325*5c591343SA. Cody Schuffelen // If the lower bits of c are greater or equal to the lower bits of t1
326*5c591343SA. Cody Schuffelen // then the upper bits of t1 must be one more than the upper bits
327*5c591343SA. Cody Schuffelen // of c
328*5c591343SA. Cody Schuffelen if((*c & COMMIT_INDEX_MASK) >= (t1 & COMMIT_INDEX_MASK))
329*5c591343SA. Cody Schuffelen // Since the counter is behind, reduce the current count
330*5c591343SA. Cody Schuffelen currentCount = currentCount - (COMMIT_INDEX_MASK + 1);
331*5c591343SA. Cody Schuffelen
332*5c591343SA. Cody Schuffelen t1 = (UINT16)currentCount;
333*5c591343SA. Cody Schuffelen if((t1 & ~COMMIT_INDEX_MASK) != (*c & ~COMMIT_INDEX_MASK))
334*5c591343SA. Cody Schuffelen return FALSE;
335*5c591343SA. Cody Schuffelen // set the counter to the value that was
336*5c591343SA. Cody Schuffelen // present when the commitment was made
337*5c591343SA. Cody Schuffelen currentCount = (currentCount & 0xffffffffffff0000) | *c;
338*5c591343SA. Cody Schuffelen }
339*5c591343SA. Cody Schuffelen // Marshal the count value to a TPM2B buffer for the KDF
340*5c591343SA. Cody Schuffelen cntr.t.size = sizeof(currentCount);
341*5c591343SA. Cody Schuffelen UINT64_TO_BYTE_ARRAY(currentCount, cntr.t.buffer);
342*5c591343SA. Cody Schuffelen
343*5c591343SA. Cody Schuffelen // Now can do the KDF to create the random value for the signing operation
344*5c591343SA. Cody Schuffelen // During the creation process, we may generate an r that does not meet the
345*5c591343SA. Cody Schuffelen // requirements of the random value.
346*5c591343SA. Cody Schuffelen // want to generate a new r.
347*5c591343SA. Cody Schuffelen r->t.size = n.t.size;
348*5c591343SA. Cody Schuffelen
349*5c591343SA. Cody Schuffelen for(iterations = 1; iterations < 1000000;)
350*5c591343SA. Cody Schuffelen {
351*5c591343SA. Cody Schuffelen int i;
352*5c591343SA. Cody Schuffelen CryptKDFa(CONTEXT_INTEGRITY_HASH_ALG, &gr.commitNonce.b, COMMIT_STRING,
353*5c591343SA. Cody Schuffelen &name->b, &cntr.b, n.t.size * 8, r->t.buffer, &iterations, FALSE);
354*5c591343SA. Cody Schuffelen
355*5c591343SA. Cody Schuffelen // "random" value must be less than the prime
356*5c591343SA. Cody Schuffelen if(UnsignedCompareB(r->b.size, r->b.buffer, n.t.size, n.t.buffer) >= 0)
357*5c591343SA. Cody Schuffelen continue;
358*5c591343SA. Cody Schuffelen
359*5c591343SA. Cody Schuffelen // in this implementation it is required that at least bit
360*5c591343SA. Cody Schuffelen // in the upper half of the number be set
361*5c591343SA. Cody Schuffelen for(i = n.t.size / 2; i >= 0; i--)
362*5c591343SA. Cody Schuffelen if(r->b.buffer[i] != 0)
363*5c591343SA. Cody Schuffelen return TRUE;
364*5c591343SA. Cody Schuffelen }
365*5c591343SA. Cody Schuffelen return FALSE;
366*5c591343SA. Cody Schuffelen }
367*5c591343SA. Cody Schuffelen
368*5c591343SA. Cody Schuffelen //*** CryptCommit()
369*5c591343SA. Cody Schuffelen // This function is called when the count value is committed. The 'gr.commitArray'
370*5c591343SA. Cody Schuffelen // value associated with the current count value is SET and g_commitCounter is
371*5c591343SA. Cody Schuffelen // incremented. The low-order 16 bits of old value of the counter is returned.
372*5c591343SA. Cody Schuffelen UINT16
CryptCommit(void)373*5c591343SA. Cody Schuffelen CryptCommit(
374*5c591343SA. Cody Schuffelen void
375*5c591343SA. Cody Schuffelen )
376*5c591343SA. Cody Schuffelen {
377*5c591343SA. Cody Schuffelen UINT16 oldCount = (UINT16)gr.commitCounter;
378*5c591343SA. Cody Schuffelen gr.commitCounter++;
379*5c591343SA. Cody Schuffelen SET_BIT(oldCount & COMMIT_INDEX_MASK, gr.commitArray);
380*5c591343SA. Cody Schuffelen return oldCount;
381*5c591343SA. Cody Schuffelen }
382*5c591343SA. Cody Schuffelen
383*5c591343SA. Cody Schuffelen //*** CryptEndCommit()
384*5c591343SA. Cody Schuffelen // This function is called when the signing operation using the committed value
385*5c591343SA. Cody Schuffelen // is completed. It clears the gr.commitArray bit associated with the count
386*5c591343SA. Cody Schuffelen // value so that it can't be used again.
387*5c591343SA. Cody Schuffelen void
CryptEndCommit(UINT16 c)388*5c591343SA. Cody Schuffelen CryptEndCommit(
389*5c591343SA. Cody Schuffelen UINT16 c // IN: the counter value of the commitment
390*5c591343SA. Cody Schuffelen )
391*5c591343SA. Cody Schuffelen {
392*5c591343SA. Cody Schuffelen ClearBit((c & COMMIT_INDEX_MASK), gr.commitArray, sizeof(gr.commitArray));
393*5c591343SA. Cody Schuffelen }
394*5c591343SA. Cody Schuffelen
395*5c591343SA. Cody Schuffelen //*** CryptEccGetParameters()
396*5c591343SA. Cody Schuffelen // This function returns the ECC parameter details of the given curve.
397*5c591343SA. Cody Schuffelen // Return Type: BOOL
398*5c591343SA. Cody Schuffelen // TRUE(1) success
399*5c591343SA. Cody Schuffelen // FALSE(0) unsupported ECC curve ID
400*5c591343SA. Cody Schuffelen BOOL
CryptEccGetParameters(TPM_ECC_CURVE curveId,TPMS_ALGORITHM_DETAIL_ECC * parameters)401*5c591343SA. Cody Schuffelen CryptEccGetParameters(
402*5c591343SA. Cody Schuffelen TPM_ECC_CURVE curveId, // IN: ECC curve ID
403*5c591343SA. Cody Schuffelen TPMS_ALGORITHM_DETAIL_ECC *parameters // OUT: ECC parameters
404*5c591343SA. Cody Schuffelen )
405*5c591343SA. Cody Schuffelen {
406*5c591343SA. Cody Schuffelen const ECC_CURVE *curve = CryptEccGetParametersByCurveId(curveId);
407*5c591343SA. Cody Schuffelen const ECC_CURVE_DATA *data;
408*5c591343SA. Cody Schuffelen BOOL found = curve != NULL;
409*5c591343SA. Cody Schuffelen
410*5c591343SA. Cody Schuffelen if(found)
411*5c591343SA. Cody Schuffelen {
412*5c591343SA. Cody Schuffelen data = curve->curveData;
413*5c591343SA. Cody Schuffelen parameters->curveID = curve->curveId;
414*5c591343SA. Cody Schuffelen parameters->keySize = curve->keySizeBits;
415*5c591343SA. Cody Schuffelen parameters->kdf = curve->kdf;
416*5c591343SA. Cody Schuffelen parameters->sign = curve->sign;
417*5c591343SA. Cody Schuffelen // BnTo2B(data->prime, ¶meters->p.b, 0);
418*5c591343SA. Cody Schuffelen BnTo2B(data->prime, ¶meters->p.b, parameters->p.t.size);
419*5c591343SA. Cody Schuffelen BnTo2B(data->a, ¶meters->a.b, 0);
420*5c591343SA. Cody Schuffelen BnTo2B(data->b, ¶meters->b.b, 0);
421*5c591343SA. Cody Schuffelen BnTo2B(data->base.x, ¶meters->gX.b, parameters->p.t.size);
422*5c591343SA. Cody Schuffelen BnTo2B(data->base.y, ¶meters->gY.b, parameters->p.t.size);
423*5c591343SA. Cody Schuffelen // BnTo2B(data->base.x, ¶meters->gX.b, 0);
424*5c591343SA. Cody Schuffelen // BnTo2B(data->base.y, ¶meters->gY.b, 0);
425*5c591343SA. Cody Schuffelen BnTo2B(data->order, ¶meters->n.b, 0);
426*5c591343SA. Cody Schuffelen BnTo2B(data->h, ¶meters->h.b, 0);
427*5c591343SA. Cody Schuffelen }
428*5c591343SA. Cody Schuffelen return found;
429*5c591343SA. Cody Schuffelen }
430*5c591343SA. Cody Schuffelen
431*5c591343SA. Cody Schuffelen //*** BnGetCurvePrime()
432*5c591343SA. Cody Schuffelen // This function is used to get just the prime modulus associated with a curve.
433*5c591343SA. Cody Schuffelen const bignum_t *
BnGetCurvePrime(TPM_ECC_CURVE curveId)434*5c591343SA. Cody Schuffelen BnGetCurvePrime(
435*5c591343SA. Cody Schuffelen TPM_ECC_CURVE curveId
436*5c591343SA. Cody Schuffelen )
437*5c591343SA. Cody Schuffelen {
438*5c591343SA. Cody Schuffelen const ECC_CURVE_DATA *C = GetCurveData(curveId);
439*5c591343SA. Cody Schuffelen return (C != NULL) ? CurveGetPrime(C) : NULL;
440*5c591343SA. Cody Schuffelen }
441*5c591343SA. Cody Schuffelen
442*5c591343SA. Cody Schuffelen //*** BnGetCurveOrder()
443*5c591343SA. Cody Schuffelen // This function is used to get just the curve order
444*5c591343SA. Cody Schuffelen const bignum_t *
BnGetCurveOrder(TPM_ECC_CURVE curveId)445*5c591343SA. Cody Schuffelen BnGetCurveOrder(
446*5c591343SA. Cody Schuffelen TPM_ECC_CURVE curveId
447*5c591343SA. Cody Schuffelen )
448*5c591343SA. Cody Schuffelen {
449*5c591343SA. Cody Schuffelen const ECC_CURVE_DATA *C = GetCurveData(curveId);
450*5c591343SA. Cody Schuffelen return (C != NULL) ? CurveGetOrder(C) : NULL;
451*5c591343SA. Cody Schuffelen }
452*5c591343SA. Cody Schuffelen
453*5c591343SA. Cody Schuffelen //*** BnIsOnCurve()
454*5c591343SA. Cody Schuffelen // This function checks if a point is on the curve.
455*5c591343SA. Cody Schuffelen BOOL
BnIsOnCurve(pointConst Q,const ECC_CURVE_DATA * C)456*5c591343SA. Cody Schuffelen BnIsOnCurve(
457*5c591343SA. Cody Schuffelen pointConst Q,
458*5c591343SA. Cody Schuffelen const ECC_CURVE_DATA *C
459*5c591343SA. Cody Schuffelen )
460*5c591343SA. Cody Schuffelen {
461*5c591343SA. Cody Schuffelen BN_VAR(right, (MAX_ECC_KEY_BITS * 3));
462*5c591343SA. Cody Schuffelen BN_VAR(left, (MAX_ECC_KEY_BITS * 2));
463*5c591343SA. Cody Schuffelen bigConst prime = CurveGetPrime(C);
464*5c591343SA. Cody Schuffelen //
465*5c591343SA. Cody Schuffelen // Show that point is on the curve y^2 = x^3 + ax + b;
466*5c591343SA. Cody Schuffelen // Or y^2 = x(x^2 + a) + b
467*5c591343SA. Cody Schuffelen // y^2
468*5c591343SA. Cody Schuffelen BnMult(left, Q->y, Q->y);
469*5c591343SA. Cody Schuffelen
470*5c591343SA. Cody Schuffelen BnMod(left, prime);
471*5c591343SA. Cody Schuffelen // x^2
472*5c591343SA. Cody Schuffelen BnMult(right, Q->x, Q->x);
473*5c591343SA. Cody Schuffelen
474*5c591343SA. Cody Schuffelen // x^2 + a
475*5c591343SA. Cody Schuffelen BnAdd(right, right, CurveGet_a(C));
476*5c591343SA. Cody Schuffelen
477*5c591343SA. Cody Schuffelen // BnMod(right, CurveGetPrime(C));
478*5c591343SA. Cody Schuffelen // x(x^2 + a)
479*5c591343SA. Cody Schuffelen BnMult(right, right, Q->x);
480*5c591343SA. Cody Schuffelen
481*5c591343SA. Cody Schuffelen // x(x^2 + a) + b
482*5c591343SA. Cody Schuffelen BnAdd(right, right, CurveGet_b(C));
483*5c591343SA. Cody Schuffelen
484*5c591343SA. Cody Schuffelen BnMod(right, prime);
485*5c591343SA. Cody Schuffelen if(BnUnsignedCmp(left, right) == 0)
486*5c591343SA. Cody Schuffelen return TRUE;
487*5c591343SA. Cody Schuffelen else
488*5c591343SA. Cody Schuffelen return FALSE;
489*5c591343SA. Cody Schuffelen }
490*5c591343SA. Cody Schuffelen
491*5c591343SA. Cody Schuffelen //*** BnIsValidPrivateEcc()
492*5c591343SA. Cody Schuffelen // Checks that 0 < 'x' < 'q'
493*5c591343SA. Cody Schuffelen BOOL
BnIsValidPrivateEcc(bigConst x,bigCurve E)494*5c591343SA. Cody Schuffelen BnIsValidPrivateEcc(
495*5c591343SA. Cody Schuffelen bigConst x, // IN: private key to check
496*5c591343SA. Cody Schuffelen bigCurve E // IN: the curve to check
497*5c591343SA. Cody Schuffelen )
498*5c591343SA. Cody Schuffelen {
499*5c591343SA. Cody Schuffelen BOOL retVal;
500*5c591343SA. Cody Schuffelen retVal = (!BnEqualZero(x)
501*5c591343SA. Cody Schuffelen && (BnUnsignedCmp(x, CurveGetOrder(AccessCurveData(E))) < 0));
502*5c591343SA. Cody Schuffelen return retVal;
503*5c591343SA. Cody Schuffelen }
504*5c591343SA. Cody Schuffelen
505*5c591343SA. Cody Schuffelen LIB_EXPORT BOOL
CryptEccIsValidPrivateKey(TPM2B_ECC_PARAMETER * d,TPM_ECC_CURVE curveId)506*5c591343SA. Cody Schuffelen CryptEccIsValidPrivateKey(
507*5c591343SA. Cody Schuffelen TPM2B_ECC_PARAMETER *d,
508*5c591343SA. Cody Schuffelen TPM_ECC_CURVE curveId
509*5c591343SA. Cody Schuffelen )
510*5c591343SA. Cody Schuffelen {
511*5c591343SA. Cody Schuffelen BN_INITIALIZED(bnD, MAX_ECC_PARAMETER_BYTES * 8, d);
512*5c591343SA. Cody Schuffelen return !BnEqualZero(bnD) && (BnUnsignedCmp(bnD, BnGetCurveOrder(curveId)) < 0);
513*5c591343SA. Cody Schuffelen }
514*5c591343SA. Cody Schuffelen
515*5c591343SA. Cody Schuffelen //*** BnPointMul()
516*5c591343SA. Cody Schuffelen // This function does a point multiply of the form 'R' = ['d']'S' + ['u']'Q' where the
517*5c591343SA. Cody Schuffelen // parameters are bigNum values. If 'S' is NULL and d is not NULL, then it computes
518*5c591343SA. Cody Schuffelen // 'R' = ['d']'G' + ['u']'Q' or just 'R' = ['d']'G' if 'u' and 'Q' are NULL.
519*5c591343SA. Cody Schuffelen // If 'skipChecks' is TRUE, then the function will not verify that the inputs are
520*5c591343SA. Cody Schuffelen // correct for the domain. This would be the case when the values were created by the
521*5c591343SA. Cody Schuffelen // CryptoEngine code.
522*5c591343SA. Cody Schuffelen // It will return TPM_RC_NO_RESULT if the resulting point is the point at infinity.
523*5c591343SA. Cody Schuffelen // Return Type: TPM_RC
524*5c591343SA. Cody Schuffelen // TPM_RC_NO_RESULT result of multiplication is a point at infinity
525*5c591343SA. Cody Schuffelen // TPM_RC_ECC_POINT 'S' or 'Q' is not on the curve
526*5c591343SA. Cody Schuffelen // TPM_RC_VALUE 'd' or 'u' is not < n
527*5c591343SA. Cody Schuffelen TPM_RC
BnPointMult(bigPoint R,pointConst S,bigConst d,pointConst Q,bigConst u,bigCurve E)528*5c591343SA. Cody Schuffelen BnPointMult(
529*5c591343SA. Cody Schuffelen bigPoint R, // OUT: computed point
530*5c591343SA. Cody Schuffelen pointConst S, // IN: optional point to multiply by 'd'
531*5c591343SA. Cody Schuffelen bigConst d, // IN: scalar for [d]S or [d]G
532*5c591343SA. Cody Schuffelen pointConst Q, // IN: optional second point
533*5c591343SA. Cody Schuffelen bigConst u, // IN: optional second scalar
534*5c591343SA. Cody Schuffelen bigCurve E // IN: curve parameters
535*5c591343SA. Cody Schuffelen )
536*5c591343SA. Cody Schuffelen {
537*5c591343SA. Cody Schuffelen BOOL OK;
538*5c591343SA. Cody Schuffelen //
539*5c591343SA. Cody Schuffelen TEST(TPM_ALG_ECDH);
540*5c591343SA. Cody Schuffelen
541*5c591343SA. Cody Schuffelen // Need one scalar
542*5c591343SA. Cody Schuffelen OK = (d != NULL || u != NULL);
543*5c591343SA. Cody Schuffelen
544*5c591343SA. Cody Schuffelen // If S is present, then d has to be present. If S is not
545*5c591343SA. Cody Schuffelen // present, then d may or may not be present
546*5c591343SA. Cody Schuffelen OK = OK && (((S == NULL) == (d == NULL)) || (d != NULL));
547*5c591343SA. Cody Schuffelen
548*5c591343SA. Cody Schuffelen // either both u and Q have to be provided or neither can be provided (don't
549*5c591343SA. Cody Schuffelen // know what to do if only one is provided.
550*5c591343SA. Cody Schuffelen OK = OK && ((u == NULL) == (Q == NULL));
551*5c591343SA. Cody Schuffelen
552*5c591343SA. Cody Schuffelen OK = OK && (E != NULL);
553*5c591343SA. Cody Schuffelen if(!OK)
554*5c591343SA. Cody Schuffelen return TPM_RC_VALUE;
555*5c591343SA. Cody Schuffelen
556*5c591343SA. Cody Schuffelen
557*5c591343SA. Cody Schuffelen OK = (S == NULL) || BnIsOnCurve(S, AccessCurveData(E));
558*5c591343SA. Cody Schuffelen OK = OK && ((Q == NULL) || BnIsOnCurve(Q, AccessCurveData(E)));
559*5c591343SA. Cody Schuffelen if(!OK)
560*5c591343SA. Cody Schuffelen return TPM_RC_ECC_POINT;
561*5c591343SA. Cody Schuffelen
562*5c591343SA. Cody Schuffelen if((d != NULL) && (S == NULL))
563*5c591343SA. Cody Schuffelen S = CurveGetG(AccessCurveData(E));
564*5c591343SA. Cody Schuffelen // If only one scalar, don't need Shamir's trick
565*5c591343SA. Cody Schuffelen if((d == NULL) || (u == NULL))
566*5c591343SA. Cody Schuffelen {
567*5c591343SA. Cody Schuffelen if(d == NULL)
568*5c591343SA. Cody Schuffelen OK = BnEccModMult(R, Q, u, E);
569*5c591343SA. Cody Schuffelen else
570*5c591343SA. Cody Schuffelen OK = BnEccModMult(R, S, d, E);
571*5c591343SA. Cody Schuffelen }
572*5c591343SA. Cody Schuffelen else
573*5c591343SA. Cody Schuffelen {
574*5c591343SA. Cody Schuffelen OK = BnEccModMult2(R, S, d, Q, u, E);
575*5c591343SA. Cody Schuffelen }
576*5c591343SA. Cody Schuffelen return (OK ? TPM_RC_SUCCESS : TPM_RC_NO_RESULT);
577*5c591343SA. Cody Schuffelen }
578*5c591343SA. Cody Schuffelen
579*5c591343SA. Cody Schuffelen //***BnEccGetPrivate()
580*5c591343SA. Cody Schuffelen // This function gets random values that are the size of the key plus 64 bits. The
581*5c591343SA. Cody Schuffelen // value is reduced (mod ('q' - 1)) and incremented by 1 ('q' is the order of the
582*5c591343SA. Cody Schuffelen // curve. This produces a value ('d') such that 1 <= 'd' < 'q'. This is the method
583*5c591343SA. Cody Schuffelen // of FIPS 186-4 Section B.4.1 ""Key Pair Generation Using Extra Random Bits"".
584*5c591343SA. Cody Schuffelen // Return Type: BOOL
585*5c591343SA. Cody Schuffelen // TRUE(1) success
586*5c591343SA. Cody Schuffelen // FALSE(0) failure generating private key
587*5c591343SA. Cody Schuffelen BOOL
BnEccGetPrivate(bigNum dOut,const ECC_CURVE_DATA * C,RAND_STATE * rand)588*5c591343SA. Cody Schuffelen BnEccGetPrivate(
589*5c591343SA. Cody Schuffelen bigNum dOut, // OUT: the qualified random value
590*5c591343SA. Cody Schuffelen const ECC_CURVE_DATA *C, // IN: curve for which the private key
591*5c591343SA. Cody Schuffelen // needs to be appropriate
592*5c591343SA. Cody Schuffelen RAND_STATE *rand // IN: state for DRBG
593*5c591343SA. Cody Schuffelen )
594*5c591343SA. Cody Schuffelen {
595*5c591343SA. Cody Schuffelen bigConst order = CurveGetOrder(C);
596*5c591343SA. Cody Schuffelen BOOL OK;
597*5c591343SA. Cody Schuffelen UINT32 orderBits = BnSizeInBits(order);
598*5c591343SA. Cody Schuffelen UINT32 orderBytes = BITS_TO_BYTES(orderBits);
599*5c591343SA. Cody Schuffelen BN_VAR(bnExtraBits, MAX_ECC_KEY_BITS + 64);
600*5c591343SA. Cody Schuffelen BN_VAR(nMinus1, MAX_ECC_KEY_BITS);
601*5c591343SA. Cody Schuffelen //
602*5c591343SA. Cody Schuffelen OK = BnGetRandomBits(bnExtraBits, (orderBytes * 8) + 64, rand);
603*5c591343SA. Cody Schuffelen OK = OK && BnSubWord(nMinus1, order, 1);
604*5c591343SA. Cody Schuffelen OK = OK && BnMod(bnExtraBits, nMinus1);
605*5c591343SA. Cody Schuffelen OK = OK && BnAddWord(dOut, bnExtraBits, 1);
606*5c591343SA. Cody Schuffelen return OK && !g_inFailureMode;
607*5c591343SA. Cody Schuffelen }
608*5c591343SA. Cody Schuffelen
609*5c591343SA. Cody Schuffelen //*** BnEccGenerateKeyPair()
610*5c591343SA. Cody Schuffelen // This function gets a private scalar from the source of random bits and does
611*5c591343SA. Cody Schuffelen // the point multiply to get the public key.
612*5c591343SA. Cody Schuffelen BOOL
BnEccGenerateKeyPair(bigNum bnD,bn_point_t * ecQ,bigCurve E,RAND_STATE * rand)613*5c591343SA. Cody Schuffelen BnEccGenerateKeyPair(
614*5c591343SA. Cody Schuffelen bigNum bnD, // OUT: private scalar
615*5c591343SA. Cody Schuffelen bn_point_t *ecQ, // OUT: public point
616*5c591343SA. Cody Schuffelen bigCurve E, // IN: curve for the point
617*5c591343SA. Cody Schuffelen RAND_STATE *rand // IN: DRBG state to use
618*5c591343SA. Cody Schuffelen )
619*5c591343SA. Cody Schuffelen {
620*5c591343SA. Cody Schuffelen BOOL OK = FALSE;
621*5c591343SA. Cody Schuffelen // Get a private scalar
622*5c591343SA. Cody Schuffelen OK = BnEccGetPrivate(bnD, AccessCurveData(E), rand);
623*5c591343SA. Cody Schuffelen
624*5c591343SA. Cody Schuffelen // Do a point multiply
625*5c591343SA. Cody Schuffelen OK = OK && BnEccModMult(ecQ, NULL, bnD, E);
626*5c591343SA. Cody Schuffelen if(!OK)
627*5c591343SA. Cody Schuffelen BnSetWord(ecQ->z, 0);
628*5c591343SA. Cody Schuffelen else
629*5c591343SA. Cody Schuffelen BnSetWord(ecQ->z, 1);
630*5c591343SA. Cody Schuffelen return OK;
631*5c591343SA. Cody Schuffelen }
632*5c591343SA. Cody Schuffelen
633*5c591343SA. Cody Schuffelen //***CryptEccNewKeyPair(***)
634*5c591343SA. Cody Schuffelen // This function creates an ephemeral ECC. It is ephemeral in that
635*5c591343SA. Cody Schuffelen // is expected that the private part of the key will be discarded
636*5c591343SA. Cody Schuffelen LIB_EXPORT TPM_RC
CryptEccNewKeyPair(TPMS_ECC_POINT * Qout,TPM2B_ECC_PARAMETER * dOut,TPM_ECC_CURVE curveId)637*5c591343SA. Cody Schuffelen CryptEccNewKeyPair(
638*5c591343SA. Cody Schuffelen TPMS_ECC_POINT *Qout, // OUT: the public point
639*5c591343SA. Cody Schuffelen TPM2B_ECC_PARAMETER *dOut, // OUT: the private scalar
640*5c591343SA. Cody Schuffelen TPM_ECC_CURVE curveId // IN: the curve for the key
641*5c591343SA. Cody Schuffelen )
642*5c591343SA. Cody Schuffelen {
643*5c591343SA. Cody Schuffelen CURVE_INITIALIZED(E, curveId);
644*5c591343SA. Cody Schuffelen POINT(ecQ);
645*5c591343SA. Cody Schuffelen ECC_NUM(bnD);
646*5c591343SA. Cody Schuffelen BOOL OK;
647*5c591343SA. Cody Schuffelen
648*5c591343SA. Cody Schuffelen if(E == NULL)
649*5c591343SA. Cody Schuffelen return TPM_RC_CURVE;
650*5c591343SA. Cody Schuffelen
651*5c591343SA. Cody Schuffelen TEST(TPM_ALG_ECDH);
652*5c591343SA. Cody Schuffelen OK = BnEccGenerateKeyPair(bnD, ecQ, E, NULL);
653*5c591343SA. Cody Schuffelen if(OK)
654*5c591343SA. Cody Schuffelen {
655*5c591343SA. Cody Schuffelen BnPointTo2B(Qout, ecQ, E);
656*5c591343SA. Cody Schuffelen BnTo2B(bnD, &dOut->b, Qout->x.t.size);
657*5c591343SA. Cody Schuffelen }
658*5c591343SA. Cody Schuffelen else
659*5c591343SA. Cody Schuffelen {
660*5c591343SA. Cody Schuffelen Qout->x.t.size = Qout->y.t.size = dOut->t.size = 0;
661*5c591343SA. Cody Schuffelen }
662*5c591343SA. Cody Schuffelen CURVE_FREE(E);
663*5c591343SA. Cody Schuffelen return OK ? TPM_RC_SUCCESS : TPM_RC_NO_RESULT;
664*5c591343SA. Cody Schuffelen }
665*5c591343SA. Cody Schuffelen
666*5c591343SA. Cody Schuffelen //*** CryptEccPointMultiply()
667*5c591343SA. Cody Schuffelen // This function computes 'R' := ['dIn']'G' + ['uIn']'QIn'. Where 'dIn' and
668*5c591343SA. Cody Schuffelen // 'uIn' are scalars, 'G' and 'QIn' are points on the specified curve and 'G' is the
669*5c591343SA. Cody Schuffelen // default generator of the curve.
670*5c591343SA. Cody Schuffelen //
671*5c591343SA. Cody Schuffelen // The 'xOut' and 'yOut' parameters are optional and may be set to NULL if not
672*5c591343SA. Cody Schuffelen // used.
673*5c591343SA. Cody Schuffelen //
674*5c591343SA. Cody Schuffelen // It is not necessary to provide 'uIn' if 'QIn' is specified but one of 'uIn' and
675*5c591343SA. Cody Schuffelen // 'dIn' must be provided. If 'dIn' and 'QIn' are specified but 'uIn' is not
676*5c591343SA. Cody Schuffelen // provided, then 'R' = ['dIn']'QIn'.
677*5c591343SA. Cody Schuffelen //
678*5c591343SA. Cody Schuffelen // If the multiply produces the point at infinity, the TPM_RC_NO_RESULT is returned.
679*5c591343SA. Cody Schuffelen //
680*5c591343SA. Cody Schuffelen // The sizes of 'xOut' and yOut' will be set to be the size of the degree of
681*5c591343SA. Cody Schuffelen // the curve
682*5c591343SA. Cody Schuffelen //
683*5c591343SA. Cody Schuffelen // It is a fatal error if 'dIn' and 'uIn' are both unspecified (NULL) or if 'Qin'
684*5c591343SA. Cody Schuffelen // or 'Rout' is unspecified.
685*5c591343SA. Cody Schuffelen //
686*5c591343SA. Cody Schuffelen // Return Type: TPM_RC
687*5c591343SA. Cody Schuffelen // TPM_RC_ECC_POINT the point 'Pin' or 'Qin' is not on the curve
688*5c591343SA. Cody Schuffelen // TPM_RC_NO_RESULT the product point is at infinity
689*5c591343SA. Cody Schuffelen // TPM_RC_CURVE bad curve
690*5c591343SA. Cody Schuffelen // TPM_RC_VALUE 'dIn' or 'uIn' out of range
691*5c591343SA. Cody Schuffelen //
692*5c591343SA. Cody Schuffelen LIB_EXPORT TPM_RC
CryptEccPointMultiply(TPMS_ECC_POINT * Rout,TPM_ECC_CURVE curveId,TPMS_ECC_POINT * Pin,TPM2B_ECC_PARAMETER * dIn,TPMS_ECC_POINT * Qin,TPM2B_ECC_PARAMETER * uIn)693*5c591343SA. Cody Schuffelen CryptEccPointMultiply(
694*5c591343SA. Cody Schuffelen TPMS_ECC_POINT *Rout, // OUT: the product point R
695*5c591343SA. Cody Schuffelen TPM_ECC_CURVE curveId, // IN: the curve to use
696*5c591343SA. Cody Schuffelen TPMS_ECC_POINT *Pin, // IN: first point (can be null)
697*5c591343SA. Cody Schuffelen TPM2B_ECC_PARAMETER *dIn, // IN: scalar value for [dIn]Qin
698*5c591343SA. Cody Schuffelen // the Pin
699*5c591343SA. Cody Schuffelen TPMS_ECC_POINT *Qin, // IN: point Q
700*5c591343SA. Cody Schuffelen TPM2B_ECC_PARAMETER *uIn // IN: scalar value for the multiplier
701*5c591343SA. Cody Schuffelen // of Q
702*5c591343SA. Cody Schuffelen )
703*5c591343SA. Cody Schuffelen {
704*5c591343SA. Cody Schuffelen CURVE_INITIALIZED(E, curveId);
705*5c591343SA. Cody Schuffelen POINT_INITIALIZED(ecP, Pin);
706*5c591343SA. Cody Schuffelen ECC_INITIALIZED(bnD, dIn); // If dIn is null, then bnD is null
707*5c591343SA. Cody Schuffelen ECC_INITIALIZED(bnU, uIn);
708*5c591343SA. Cody Schuffelen POINT_INITIALIZED(ecQ, Qin);
709*5c591343SA. Cody Schuffelen POINT(ecR);
710*5c591343SA. Cody Schuffelen TPM_RC retVal;
711*5c591343SA. Cody Schuffelen //
712*5c591343SA. Cody Schuffelen retVal = BnPointMult(ecR, ecP, bnD, ecQ, bnU, E);
713*5c591343SA. Cody Schuffelen
714*5c591343SA. Cody Schuffelen if(retVal == TPM_RC_SUCCESS)
715*5c591343SA. Cody Schuffelen BnPointTo2B(Rout, ecR, E);
716*5c591343SA. Cody Schuffelen else
717*5c591343SA. Cody Schuffelen ClearPoint2B(Rout);
718*5c591343SA. Cody Schuffelen CURVE_FREE(E);
719*5c591343SA. Cody Schuffelen return retVal;
720*5c591343SA. Cody Schuffelen }
721*5c591343SA. Cody Schuffelen
722*5c591343SA. Cody Schuffelen //*** CryptEccIsPointOnCurve()
723*5c591343SA. Cody Schuffelen // This function is used to test if a point is on a defined curve. It does this
724*5c591343SA. Cody Schuffelen // by checking that 'y'^2 mod 'p' = 'x'^3 + 'a'*'x' + 'b' mod 'p'.
725*5c591343SA. Cody Schuffelen //
726*5c591343SA. Cody Schuffelen // It is a fatal error if 'Q' is not specified (is NULL).
727*5c591343SA. Cody Schuffelen // Return Type: BOOL
728*5c591343SA. Cody Schuffelen // TRUE(1) point is on curve
729*5c591343SA. Cody Schuffelen // FALSE(0) point is not on curve or curve is not supported
730*5c591343SA. Cody Schuffelen LIB_EXPORT BOOL
CryptEccIsPointOnCurve(TPM_ECC_CURVE curveId,TPMS_ECC_POINT * Qin)731*5c591343SA. Cody Schuffelen CryptEccIsPointOnCurve(
732*5c591343SA. Cody Schuffelen TPM_ECC_CURVE curveId, // IN: the curve selector
733*5c591343SA. Cody Schuffelen TPMS_ECC_POINT *Qin // IN: the point.
734*5c591343SA. Cody Schuffelen )
735*5c591343SA. Cody Schuffelen {
736*5c591343SA. Cody Schuffelen const ECC_CURVE_DATA *C = GetCurveData(curveId);
737*5c591343SA. Cody Schuffelen POINT_INITIALIZED(ecQ, Qin);
738*5c591343SA. Cody Schuffelen BOOL OK;
739*5c591343SA. Cody Schuffelen //
740*5c591343SA. Cody Schuffelen pAssert(Qin != NULL);
741*5c591343SA. Cody Schuffelen OK = (C != NULL && (BnIsOnCurve(ecQ, C)));
742*5c591343SA. Cody Schuffelen return OK;
743*5c591343SA. Cody Schuffelen }
744*5c591343SA. Cody Schuffelen
745*5c591343SA. Cody Schuffelen //*** CryptEccGenerateKey()
746*5c591343SA. Cody Schuffelen // This function generates an ECC key pair based on the input parameters.
747*5c591343SA. Cody Schuffelen // This routine uses KDFa to produce candidate numbers. The method is according
748*5c591343SA. Cody Schuffelen // to FIPS 186-3, section B.1.2 "Key Pair Generation by Testing Candidates."
749*5c591343SA. Cody Schuffelen // According to the method in FIPS 186-3, the resulting private value 'd' should be
750*5c591343SA. Cody Schuffelen // 1 <= 'd' < 'n' where 'n' is the order of the base point.
751*5c591343SA. Cody Schuffelen //
752*5c591343SA. Cody Schuffelen // It is a fatal error if 'Qout', 'dOut', is not provided (is NULL).
753*5c591343SA. Cody Schuffelen //
754*5c591343SA. Cody Schuffelen // If the curve is not supported
755*5c591343SA. Cody Schuffelen // If 'seed' is not provided, then a random number will be used for the key
756*5c591343SA. Cody Schuffelen // Return Type: TPM_RC
757*5c591343SA. Cody Schuffelen // TPM_RC_CURVE curve is not supported
758*5c591343SA. Cody Schuffelen // TPM_RC_NO_RESULT could not verify key with signature (FIPS only)
759*5c591343SA. Cody Schuffelen LIB_EXPORT TPM_RC
CryptEccGenerateKey(TPMT_PUBLIC * publicArea,TPMT_SENSITIVE * sensitive,RAND_STATE * rand)760*5c591343SA. Cody Schuffelen CryptEccGenerateKey(
761*5c591343SA. Cody Schuffelen TPMT_PUBLIC *publicArea, // IN/OUT: The public area template for
762*5c591343SA. Cody Schuffelen // the new key. The public key
763*5c591343SA. Cody Schuffelen // area will be replaced computed
764*5c591343SA. Cody Schuffelen // ECC public key
765*5c591343SA. Cody Schuffelen TPMT_SENSITIVE *sensitive, // OUT: the sensitive area will be
766*5c591343SA. Cody Schuffelen // updated to contain the private
767*5c591343SA. Cody Schuffelen // ECC key and the symmetric
768*5c591343SA. Cody Schuffelen // encryption key
769*5c591343SA. Cody Schuffelen RAND_STATE *rand // IN: if not NULL, the deterministic
770*5c591343SA. Cody Schuffelen // RNG state
771*5c591343SA. Cody Schuffelen )
772*5c591343SA. Cody Schuffelen {
773*5c591343SA. Cody Schuffelen CURVE_INITIALIZED(E, publicArea->parameters.eccDetail.curveID);
774*5c591343SA. Cody Schuffelen ECC_NUM(bnD);
775*5c591343SA. Cody Schuffelen POINT(ecQ);
776*5c591343SA. Cody Schuffelen BOOL OK;
777*5c591343SA. Cody Schuffelen TPM_RC retVal;
778*5c591343SA. Cody Schuffelen //
779*5c591343SA. Cody Schuffelen TEST(TPM_ALG_ECDSA); // ECDSA is used to verify each key
780*5c591343SA. Cody Schuffelen
781*5c591343SA. Cody Schuffelen // Validate parameters
782*5c591343SA. Cody Schuffelen if(E == NULL)
783*5c591343SA. Cody Schuffelen ERROR_RETURN(TPM_RC_CURVE);
784*5c591343SA. Cody Schuffelen
785*5c591343SA. Cody Schuffelen publicArea->unique.ecc.x.t.size = 0;
786*5c591343SA. Cody Schuffelen publicArea->unique.ecc.y.t.size = 0;
787*5c591343SA. Cody Schuffelen sensitive->sensitive.ecc.t.size = 0;
788*5c591343SA. Cody Schuffelen
789*5c591343SA. Cody Schuffelen OK = BnEccGenerateKeyPair(bnD, ecQ, E, rand);
790*5c591343SA. Cody Schuffelen if(OK)
791*5c591343SA. Cody Schuffelen {
792*5c591343SA. Cody Schuffelen BnPointTo2B(&publicArea->unique.ecc, ecQ, E);
793*5c591343SA. Cody Schuffelen BnTo2B(bnD, &sensitive->sensitive.ecc.b, publicArea->unique.ecc.x.t.size);
794*5c591343SA. Cody Schuffelen }
795*5c591343SA. Cody Schuffelen #if FIPS_COMPLIANT
796*5c591343SA. Cody Schuffelen // See if PWCT is required
797*5c591343SA. Cody Schuffelen if(OK && IS_ATTRIBUTE(publicArea->objectAttributes, TPMA_OBJECT, sign))
798*5c591343SA. Cody Schuffelen {
799*5c591343SA. Cody Schuffelen ECC_NUM(bnT);
800*5c591343SA. Cody Schuffelen ECC_NUM(bnS);
801*5c591343SA. Cody Schuffelen TPM2B_DIGEST digest;
802*5c591343SA. Cody Schuffelen //
803*5c591343SA. Cody Schuffelen TEST(TPM_ALG_ECDSA);
804*5c591343SA. Cody Schuffelen digest.t.size = MIN(sensitive->sensitive.ecc.t.size, sizeof(digest.t.buffer));
805*5c591343SA. Cody Schuffelen // Get a random value to sign using the built in DRBG state
806*5c591343SA. Cody Schuffelen DRBG_Generate(NULL, digest.t.buffer, digest.t.size);
807*5c591343SA. Cody Schuffelen if(g_inFailureMode)
808*5c591343SA. Cody Schuffelen return TPM_RC_FAILURE;
809*5c591343SA. Cody Schuffelen BnSignEcdsa(bnT, bnS, E, bnD, &digest, NULL);
810*5c591343SA. Cody Schuffelen // and make sure that we can validate the signature
811*5c591343SA. Cody Schuffelen OK = BnValidateSignatureEcdsa(bnT, bnS, E, ecQ, &digest) == TPM_RC_SUCCESS;
812*5c591343SA. Cody Schuffelen }
813*5c591343SA. Cody Schuffelen #endif
814*5c591343SA. Cody Schuffelen retVal = (OK) ? TPM_RC_SUCCESS : TPM_RC_NO_RESULT;
815*5c591343SA. Cody Schuffelen Exit:
816*5c591343SA. Cody Schuffelen CURVE_FREE(E);
817*5c591343SA. Cody Schuffelen return retVal;
818*5c591343SA. Cody Schuffelen }
819*5c591343SA. Cody Schuffelen
820*5c591343SA. Cody Schuffelen #endif // ALG_ECC