xref: /aosp_15_r20/external/ms-tpm-20-ref/TPMCmd/tpm/src/crypt/CryptEccMain.c (revision 5c591343844d1f9da7da26467c4bf7efc8a7a413)
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, &parameters->p.b, 0);
418*5c591343SA. Cody Schuffelen         BnTo2B(data->prime, &parameters->p.b, parameters->p.t.size);
419*5c591343SA. Cody Schuffelen         BnTo2B(data->a, &parameters->a.b, 0);
420*5c591343SA. Cody Schuffelen         BnTo2B(data->b, &parameters->b.b, 0);
421*5c591343SA. Cody Schuffelen         BnTo2B(data->base.x, &parameters->gX.b, parameters->p.t.size);
422*5c591343SA. Cody Schuffelen         BnTo2B(data->base.y, &parameters->gY.b, parameters->p.t.size);
423*5c591343SA. Cody Schuffelen //        BnTo2B(data->base.x, &parameters->gX.b, 0);
424*5c591343SA. Cody Schuffelen //        BnTo2B(data->base.y, &parameters->gY.b, 0);
425*5c591343SA. Cody Schuffelen         BnTo2B(data->order, &parameters->n.b, 0);
426*5c591343SA. Cody Schuffelen         BnTo2B(data->h, &parameters->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