xref: /aosp_15_r20/external/ms-tpm-20-ref/TPMCmd/tpm/src/crypt/CryptEccSignature.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 #include "CryptEccSignature_fp.h"
38*5c591343SA. Cody Schuffelen 
39*5c591343SA. Cody Schuffelen #if ALG_ECC
40*5c591343SA. Cody Schuffelen 
41*5c591343SA. Cody Schuffelen //** Utility Functions
42*5c591343SA. Cody Schuffelen 
43*5c591343SA. Cody Schuffelen //*** EcdsaDigest()
44*5c591343SA. Cody Schuffelen // Function to adjust the digest so that it is no larger than the order of the
45*5c591343SA. Cody Schuffelen // curve. This is used for ECDSA sign and verification.
46*5c591343SA. Cody Schuffelen static bigNum
EcdsaDigest(bigNum bnD,const TPM2B_DIGEST * digest,bigConst max)47*5c591343SA. Cody Schuffelen EcdsaDigest(
48*5c591343SA. Cody Schuffelen     bigNum               bnD,           // OUT: the adjusted digest
49*5c591343SA. Cody Schuffelen     const TPM2B_DIGEST  *digest,        // IN: digest to adjust
50*5c591343SA. Cody Schuffelen     bigConst             max            // IN: value that indicates the maximum
51*5c591343SA. Cody Schuffelen                                         //     number of bits in the results
52*5c591343SA. Cody Schuffelen     )
53*5c591343SA. Cody Schuffelen {
54*5c591343SA. Cody Schuffelen     int              bitsInMax = BnSizeInBits(max);
55*5c591343SA. Cody Schuffelen     int              shift;
56*5c591343SA. Cody Schuffelen //
57*5c591343SA. Cody Schuffelen     if(digest == NULL)
58*5c591343SA. Cody Schuffelen         BnSetWord(bnD, 0);
59*5c591343SA. Cody Schuffelen     else
60*5c591343SA. Cody Schuffelen     {
61*5c591343SA. Cody Schuffelen         BnFromBytes(bnD, digest->t.buffer,
62*5c591343SA. Cody Schuffelen                     (NUMBYTES)MIN(digest->t.size, BITS_TO_BYTES(bitsInMax)));
63*5c591343SA. Cody Schuffelen         shift = BnSizeInBits(bnD) - bitsInMax;
64*5c591343SA. Cody Schuffelen         if(shift > 0)
65*5c591343SA. Cody Schuffelen             BnShiftRight(bnD, bnD, shift);
66*5c591343SA. Cody Schuffelen     }
67*5c591343SA. Cody Schuffelen     return bnD;
68*5c591343SA. Cody Schuffelen }
69*5c591343SA. Cody Schuffelen 
70*5c591343SA. Cody Schuffelen //*** BnSchnorrSign()
71*5c591343SA. Cody Schuffelen // This contains the Schnorr signature computation. It is used by both ECDSA and
72*5c591343SA. Cody Schuffelen // Schnorr signing. The result is computed as: ['s' = 'k' + 'r' * 'd' (mod 'n')]
73*5c591343SA. Cody Schuffelen // where
74*5c591343SA. Cody Schuffelen // 1) 's' is the signature
75*5c591343SA. Cody Schuffelen // 2) 'k' is a random value
76*5c591343SA. Cody Schuffelen // 3) 'r' is the value to sign
77*5c591343SA. Cody Schuffelen // 4) 'd' is the private EC key
78*5c591343SA. Cody Schuffelen // 5) 'n' is the order of the curve
79*5c591343SA. Cody Schuffelen //  Return Type: TPM_RC
80*5c591343SA. Cody Schuffelen //      TPM_RC_NO_RESULT        the result of the operation was zero or 'r' (mod 'n')
81*5c591343SA. Cody Schuffelen //                              is zero
82*5c591343SA. Cody Schuffelen static TPM_RC
BnSchnorrSign(bigNum bnS,bigConst bnK,bigNum bnR,bigConst bnD,bigConst bnN)83*5c591343SA. Cody Schuffelen BnSchnorrSign(
84*5c591343SA. Cody Schuffelen     bigNum                   bnS,           // OUT: 's' component of the signature
85*5c591343SA. Cody Schuffelen     bigConst                 bnK,           // IN: a random value
86*5c591343SA. Cody Schuffelen     bigNum                   bnR,           // IN: the signature 'r' value
87*5c591343SA. Cody Schuffelen     bigConst                 bnD,           // IN: the private key
88*5c591343SA. Cody Schuffelen     bigConst                 bnN            // IN: the order of the curve
89*5c591343SA. Cody Schuffelen     )
90*5c591343SA. Cody Schuffelen {
91*5c591343SA. Cody Schuffelen     // Need a local temp value to store the intermediate computation because product
92*5c591343SA. Cody Schuffelen     // size can be larger than will fit in bnS.
93*5c591343SA. Cody Schuffelen     BN_VAR(bnT1, MAX_ECC_PARAMETER_BYTES * 2 * 8);
94*5c591343SA. Cody Schuffelen //
95*5c591343SA. Cody Schuffelen     // Reduce bnR without changing the input value
96*5c591343SA. Cody Schuffelen     BnDiv(NULL, bnT1, bnR, bnN);
97*5c591343SA. Cody Schuffelen     if(BnEqualZero(bnT1))
98*5c591343SA. Cody Schuffelen         return TPM_RC_NO_RESULT;
99*5c591343SA. Cody Schuffelen     // compute s = (k + r * d)(mod n)
100*5c591343SA. Cody Schuffelen         // r * d
101*5c591343SA. Cody Schuffelen     BnMult(bnT1, bnT1, bnD);
102*5c591343SA. Cody Schuffelen         // k * r * d
103*5c591343SA. Cody Schuffelen     BnAdd(bnT1, bnT1, bnK);
104*5c591343SA. Cody Schuffelen         // k + r * d (mod n)
105*5c591343SA. Cody Schuffelen     BnDiv(NULL, bnS, bnT1, bnN);
106*5c591343SA. Cody Schuffelen     return (BnEqualZero(bnS)) ? TPM_RC_NO_RESULT : TPM_RC_SUCCESS;
107*5c591343SA. Cody Schuffelen }
108*5c591343SA. Cody Schuffelen 
109*5c591343SA. Cody Schuffelen //** Signing Functions
110*5c591343SA. Cody Schuffelen 
111*5c591343SA. Cody Schuffelen //*** BnSignEcdsa()
112*5c591343SA. Cody Schuffelen // This function implements the ECDSA signing algorithm. The method is described
113*5c591343SA. Cody Schuffelen // in the comments below.
114*5c591343SA. Cody Schuffelen TPM_RC
BnSignEcdsa(bigNum bnR,bigNum bnS,bigCurve E,bigNum bnD,const TPM2B_DIGEST * digest,RAND_STATE * rand)115*5c591343SA. Cody Schuffelen BnSignEcdsa(
116*5c591343SA. Cody Schuffelen     bigNum                   bnR,           // OUT: 'r' component of the signature
117*5c591343SA. Cody Schuffelen     bigNum                   bnS,           // OUT: 's' component of the signature
118*5c591343SA. Cody Schuffelen     bigCurve                 E,             // IN: the curve used in the signature
119*5c591343SA. Cody Schuffelen                                             //     process
120*5c591343SA. Cody Schuffelen     bigNum                   bnD,           // IN: private signing key
121*5c591343SA. Cody Schuffelen     const TPM2B_DIGEST      *digest,        // IN: the digest to sign
122*5c591343SA. Cody Schuffelen     RAND_STATE              *rand           // IN: used in debug of signing
123*5c591343SA. Cody Schuffelen     )
124*5c591343SA. Cody Schuffelen {
125*5c591343SA. Cody Schuffelen     ECC_NUM(bnK);
126*5c591343SA. Cody Schuffelen     ECC_NUM(bnIk);
127*5c591343SA. Cody Schuffelen     BN_VAR(bnE, MAX(MAX_ECC_KEY_BYTES, MAX_DIGEST_SIZE) * 8);
128*5c591343SA. Cody Schuffelen     POINT(ecR);
129*5c591343SA. Cody Schuffelen     bigConst                order = CurveGetOrder(AccessCurveData(E));
130*5c591343SA. Cody Schuffelen     TPM_RC                  retVal = TPM_RC_SUCCESS;
131*5c591343SA. Cody Schuffelen     INT32                   tries = 10;
132*5c591343SA. Cody Schuffelen     BOOL                    OK = FALSE;
133*5c591343SA. Cody Schuffelen //
134*5c591343SA. Cody Schuffelen     pAssert(digest != NULL);
135*5c591343SA. Cody Schuffelen     // The algorithm as described in "Suite B Implementer's Guide to FIPS
136*5c591343SA. Cody Schuffelen     // 186-3(ECDSA)"
137*5c591343SA. Cody Schuffelen     // 1. Use one of the routines in Appendix A.2 to generate (k, k^-1), a
138*5c591343SA. Cody Schuffelen     //    per-message secret number and its inverse modulo n. Since n is prime,
139*5c591343SA. Cody Schuffelen     //    the output will be invalid only if there is a failure in the RBG.
140*5c591343SA. Cody Schuffelen     // 2. Compute the elliptic curve point R = [k]G = (xR, yR) using EC scalar
141*5c591343SA. Cody Schuffelen     //    multiplication (see [Routines]), where G is the base point included in
142*5c591343SA. Cody Schuffelen     //    the set of domain parameters.
143*5c591343SA. Cody Schuffelen     // 3. Compute r = xR mod n. If r = 0, then return to Step 1. 1.
144*5c591343SA. Cody Schuffelen     // 4. Use the selected hash function to compute H = Hash(M).
145*5c591343SA. Cody Schuffelen     // 5. Convert the bit string H to an integer e as described in Appendix B.2.
146*5c591343SA. Cody Schuffelen     // 6. Compute s = (k^-1 *  (e + d *  r)) mod q. If s = 0, return to Step 1.2.
147*5c591343SA. Cody Schuffelen     // 7. Return (r, s).
148*5c591343SA. Cody Schuffelen     // In the code below, q is n (that it, the order of the curve is p)
149*5c591343SA. Cody Schuffelen 
150*5c591343SA. Cody Schuffelen     do // This implements the loop at step 6. If s is zero, start over.
151*5c591343SA. Cody Schuffelen     {
152*5c591343SA. Cody Schuffelen         for(; tries > 0; tries--)
153*5c591343SA. Cody Schuffelen         {
154*5c591343SA. Cody Schuffelen             // Step 1 and 2 -- generate an ephemeral key and the modular inverse
155*5c591343SA. Cody Schuffelen             // of the private key.
156*5c591343SA. Cody Schuffelen             if(!BnEccGenerateKeyPair(bnK, ecR, E, rand))
157*5c591343SA. Cody Schuffelen                 continue;
158*5c591343SA. Cody Schuffelen          // x coordinate is mod p.  Make it mod q
159*5c591343SA. Cody Schuffelen             BnMod(ecR->x, order);
160*5c591343SA. Cody Schuffelen             // Make sure that it is not zero;
161*5c591343SA. Cody Schuffelen             if(BnEqualZero(ecR->x))
162*5c591343SA. Cody Schuffelen                 continue;
163*5c591343SA. Cody Schuffelen             // write the modular reduced version of r as part of the signature
164*5c591343SA. Cody Schuffelen             BnCopy(bnR, ecR->x);
165*5c591343SA. Cody Schuffelen             // Make sure that a modular inverse exists and try again if not
166*5c591343SA. Cody Schuffelen             OK = (BnModInverse(bnIk, bnK, order));
167*5c591343SA. Cody Schuffelen             if(OK)
168*5c591343SA. Cody Schuffelen                 break;
169*5c591343SA. Cody Schuffelen         }
170*5c591343SA. Cody Schuffelen         if(!OK)
171*5c591343SA. Cody Schuffelen             goto Exit;
172*5c591343SA. Cody Schuffelen 
173*5c591343SA. Cody Schuffelen         EcdsaDigest(bnE, digest, order);
174*5c591343SA. Cody Schuffelen 
175*5c591343SA. Cody Schuffelen         // now have inverse of K (bnIk), e (bnE), r (bnR),  d (bnD) and
176*5c591343SA. Cody Schuffelen         // CurveGetOrder(E)
177*5c591343SA. Cody Schuffelen         // Compute s = k^-1 (e + r*d)(mod q)
178*5c591343SA. Cody Schuffelen         //  first do s = r*d mod q
179*5c591343SA. Cody Schuffelen         BnModMult(bnS, bnR, bnD, order);
180*5c591343SA. Cody Schuffelen         // s = e + s = e + r * d
181*5c591343SA. Cody Schuffelen         BnAdd(bnS, bnE, bnS);
182*5c591343SA. Cody Schuffelen         // s = k^(-1)s (mod n) = k^(-1)(e + r * d)(mod n)
183*5c591343SA. Cody Schuffelen         BnModMult(bnS, bnIk, bnS, order);
184*5c591343SA. Cody Schuffelen 
185*5c591343SA. Cody Schuffelen         // If S is zero, try again
186*5c591343SA. Cody Schuffelen     } while(BnEqualZero(bnS));
187*5c591343SA. Cody Schuffelen Exit:
188*5c591343SA. Cody Schuffelen     return retVal;
189*5c591343SA. Cody Schuffelen }
190*5c591343SA. Cody Schuffelen 
191*5c591343SA. Cody Schuffelen #if ALG_ECDAA
192*5c591343SA. Cody Schuffelen 
193*5c591343SA. Cody Schuffelen //*** BnSignEcdaa()
194*5c591343SA. Cody Schuffelen //
195*5c591343SA. Cody Schuffelen // This function performs 's' = 'r' + 'T' * 'd' mod 'q' where
196*5c591343SA. Cody Schuffelen // 1) 'r' is a random, or pseudo-random value created in the commit phase
197*5c591343SA. Cody Schuffelen // 2) 'nonceK' is a TPM-generated, random value 0 < 'nonceK' < 'n'
198*5c591343SA. Cody Schuffelen // 3) 'T' is mod 'q' of "Hash"('nonceK' || 'digest'), and
199*5c591343SA. Cody Schuffelen // 4) 'd' is a private key.
200*5c591343SA. Cody Schuffelen //
201*5c591343SA. Cody Schuffelen // The signature is the tuple ('nonceK', 's')
202*5c591343SA. Cody Schuffelen //
203*5c591343SA. Cody Schuffelen // Regrettably, the parameters in this function kind of collide with the parameter
204*5c591343SA. Cody Schuffelen // names used in ECSCHNORR making for a lot of confusion.
205*5c591343SA. Cody Schuffelen //  Return Type: TPM_RC
206*5c591343SA. Cody Schuffelen //      TPM_RC_SCHEME       unsupported hash algorithm
207*5c591343SA. Cody Schuffelen //      TPM_RC_NO_RESULT    cannot get values from random number generator
208*5c591343SA. Cody Schuffelen static TPM_RC
BnSignEcdaa(TPM2B_ECC_PARAMETER * nonceK,bigNum bnS,bigCurve E,bigNum bnD,const TPM2B_DIGEST * digest,TPMT_ECC_SCHEME * scheme,OBJECT * eccKey,RAND_STATE * rand)209*5c591343SA. Cody Schuffelen BnSignEcdaa(
210*5c591343SA. Cody Schuffelen     TPM2B_ECC_PARAMETER     *nonceK,        // OUT: 'nonce' component of the signature
211*5c591343SA. Cody Schuffelen     bigNum                   bnS,           // OUT: 's' component of the signature
212*5c591343SA. Cody Schuffelen     bigCurve                 E,             // IN: the curve used in signing
213*5c591343SA. Cody Schuffelen     bigNum                   bnD,           // IN: the private key
214*5c591343SA. Cody Schuffelen     const TPM2B_DIGEST      *digest,        // IN: the value to sign (mod 'q')
215*5c591343SA. Cody Schuffelen     TPMT_ECC_SCHEME         *scheme,        // IN: signing scheme (contains the
216*5c591343SA. Cody Schuffelen                                             //      commit count value).
217*5c591343SA. Cody Schuffelen     OBJECT                  *eccKey,        // IN: The signing key
218*5c591343SA. Cody Schuffelen     RAND_STATE              *rand           // IN: a random number state
219*5c591343SA. Cody Schuffelen     )
220*5c591343SA. Cody Schuffelen {
221*5c591343SA. Cody Schuffelen     TPM_RC                   retVal;
222*5c591343SA. Cody Schuffelen     TPM2B_ECC_PARAMETER      r;
223*5c591343SA. Cody Schuffelen     HASH_STATE               state;
224*5c591343SA. Cody Schuffelen     TPM2B_DIGEST             T;
225*5c591343SA. Cody Schuffelen     BN_MAX(bnT);
226*5c591343SA. Cody Schuffelen //
227*5c591343SA. Cody Schuffelen     NOT_REFERENCED(rand);
228*5c591343SA. Cody Schuffelen     if(!CryptGenerateR(&r, &scheme->details.ecdaa.count,
229*5c591343SA. Cody Schuffelen                        eccKey->publicArea.parameters.eccDetail.curveID,
230*5c591343SA. Cody Schuffelen                        &eccKey->name))
231*5c591343SA. Cody Schuffelen         retVal = TPM_RC_VALUE;
232*5c591343SA. Cody Schuffelen     else
233*5c591343SA. Cody Schuffelen     {
234*5c591343SA. Cody Schuffelen         // This allocation is here because 'r' doesn't have a value until
235*5c591343SA. Cody Schuffelen         // CrypGenerateR() is done.
236*5c591343SA. Cody Schuffelen         ECC_INITIALIZED(bnR, &r);
237*5c591343SA. Cody Schuffelen         do
238*5c591343SA. Cody Schuffelen         {
239*5c591343SA. Cody Schuffelen             // generate nonceK such that 0 < nonceK < n
240*5c591343SA. Cody Schuffelen             // use bnT as a temp.
241*5c591343SA. Cody Schuffelen             if(!BnEccGetPrivate(bnT, AccessCurveData(E), rand))
242*5c591343SA. Cody Schuffelen             {
243*5c591343SA. Cody Schuffelen                 retVal = TPM_RC_NO_RESULT;
244*5c591343SA. Cody Schuffelen                 break;
245*5c591343SA. Cody Schuffelen             }
246*5c591343SA. Cody Schuffelen             BnTo2B(bnT, &nonceK->b, 0);
247*5c591343SA. Cody Schuffelen 
248*5c591343SA. Cody Schuffelen             T.t.size = CryptHashStart(&state, scheme->details.ecdaa.hashAlg);
249*5c591343SA. Cody Schuffelen             if(T.t.size == 0)
250*5c591343SA. Cody Schuffelen             {
251*5c591343SA. Cody Schuffelen                 retVal = TPM_RC_SCHEME;
252*5c591343SA. Cody Schuffelen             }
253*5c591343SA. Cody Schuffelen             else
254*5c591343SA. Cody Schuffelen             {
255*5c591343SA. Cody Schuffelen                 CryptDigestUpdate2B(&state, &nonceK->b);
256*5c591343SA. Cody Schuffelen                 CryptDigestUpdate2B(&state, &digest->b);
257*5c591343SA. Cody Schuffelen                 CryptHashEnd2B(&state, &T.b);
258*5c591343SA. Cody Schuffelen                 BnFrom2B(bnT, &T.b);
259*5c591343SA. Cody Schuffelen                 // Watch out for the name collisions in this call!!
260*5c591343SA. Cody Schuffelen                 retVal = BnSchnorrSign(bnS, bnR, bnT, bnD,
261*5c591343SA. Cody Schuffelen                                        AccessCurveData(E)->order);
262*5c591343SA. Cody Schuffelen             }
263*5c591343SA. Cody Schuffelen         } while(retVal == TPM_RC_NO_RESULT);
264*5c591343SA. Cody Schuffelen         // Because the rule is that internal state is not modified if the command
265*5c591343SA. Cody Schuffelen         // fails, only end the commit if the command succeeds.
266*5c591343SA. Cody Schuffelen         // NOTE that if the result of the Schnorr computation was zero
267*5c591343SA. Cody Schuffelen         // it will probably not be worthwhile to run the same command again because
268*5c591343SA. Cody Schuffelen         // the result will still be zero. This means that the Commit command will
269*5c591343SA. Cody Schuffelen         // need to be run again to get a new commit value for the signature.
270*5c591343SA. Cody Schuffelen         if(retVal == TPM_RC_SUCCESS)
271*5c591343SA. Cody Schuffelen             CryptEndCommit(scheme->details.ecdaa.count);
272*5c591343SA. Cody Schuffelen     }
273*5c591343SA. Cody Schuffelen     return retVal;
274*5c591343SA. Cody Schuffelen }
275*5c591343SA. Cody Schuffelen #endif // ALG_ECDAA
276*5c591343SA. Cody Schuffelen 
277*5c591343SA. Cody Schuffelen #if ALG_ECSCHNORR
278*5c591343SA. Cody Schuffelen 
279*5c591343SA. Cody Schuffelen //*** SchnorrReduce()
280*5c591343SA. Cody Schuffelen // Function to reduce a hash result if it's magnitude is too large. The size of
281*5c591343SA. Cody Schuffelen // 'number' is set so that it has no more bytes of significance than 'reference'
282*5c591343SA. Cody Schuffelen // value. If the resulting number can have more bits of significance than
283*5c591343SA. Cody Schuffelen // 'reference'.
284*5c591343SA. Cody Schuffelen static void
SchnorrReduce(TPM2B * number,bigConst reference)285*5c591343SA. Cody Schuffelen SchnorrReduce(
286*5c591343SA. Cody Schuffelen     TPM2B       *number,        // IN/OUT: Value to reduce
287*5c591343SA. Cody Schuffelen     bigConst     reference      // IN: the reference value
288*5c591343SA. Cody Schuffelen     )
289*5c591343SA. Cody Schuffelen {
290*5c591343SA. Cody Schuffelen     UINT16      maxBytes = (UINT16)BITS_TO_BYTES(BnSizeInBits(reference));
291*5c591343SA. Cody Schuffelen     if(number->size > maxBytes)
292*5c591343SA. Cody Schuffelen         number->size = maxBytes;
293*5c591343SA. Cody Schuffelen }
294*5c591343SA. Cody Schuffelen 
295*5c591343SA. Cody Schuffelen //*** SchnorrEcc()
296*5c591343SA. Cody Schuffelen // This function is used to perform a modified Schnorr signature.
297*5c591343SA. Cody Schuffelen //
298*5c591343SA. Cody Schuffelen // This function will generate a random value 'k' and compute
299*5c591343SA. Cody Schuffelen // a) ('xR', 'yR') = ['k']'G'
300*5c591343SA. Cody Schuffelen // b) 'r' = "Hash"('xR' || 'P')(mod 'q')
301*5c591343SA. Cody Schuffelen // c) 'rT' = truncated 'r'
302*5c591343SA. Cody Schuffelen // d) 's'= 'k' + 'rT' * 'ds' (mod 'q')
303*5c591343SA. Cody Schuffelen // e) return the tuple 'rT', 's'
304*5c591343SA. Cody Schuffelen //
305*5c591343SA. Cody Schuffelen //  Return Type: TPM_RC
306*5c591343SA. Cody Schuffelen //      TPM_RC_NO_RESULT        failure in the Schnorr sign process
307*5c591343SA. Cody Schuffelen //      TPM_RC_SCHEME           hashAlg can't produce zero-length digest
308*5c591343SA. Cody Schuffelen static TPM_RC
BnSignEcSchnorr(bigNum bnR,bigNum bnS,bigCurve E,bigNum bnD,const TPM2B_DIGEST * digest,TPM_ALG_ID hashAlg,RAND_STATE * rand)309*5c591343SA. Cody Schuffelen BnSignEcSchnorr(
310*5c591343SA. Cody Schuffelen     bigNum                   bnR,           // OUT: 'r' component of the signature
311*5c591343SA. Cody Schuffelen     bigNum                   bnS,           // OUT: 's' component of the signature
312*5c591343SA. Cody Schuffelen     bigCurve                 E,             // IN: the curve used in signing
313*5c591343SA. Cody Schuffelen     bigNum                   bnD,           // IN: the signing key
314*5c591343SA. Cody Schuffelen     const TPM2B_DIGEST      *digest,        // IN: the digest to sign
315*5c591343SA. Cody Schuffelen     TPM_ALG_ID               hashAlg,       // IN: signing scheme (contains a hash)
316*5c591343SA. Cody Schuffelen     RAND_STATE              *rand           // IN: non-NULL when testing
317*5c591343SA. Cody Schuffelen     )
318*5c591343SA. Cody Schuffelen {
319*5c591343SA. Cody Schuffelen     HASH_STATE               hashState;
320*5c591343SA. Cody Schuffelen     UINT16                   digestSize = CryptHashGetDigestSize(hashAlg);
321*5c591343SA. Cody Schuffelen     TPM2B_TYPE(T, MAX(MAX_DIGEST_SIZE, MAX_ECC_KEY_BYTES));
322*5c591343SA. Cody Schuffelen     TPM2B_T                  T2b;
323*5c591343SA. Cody Schuffelen     TPM2B                   *e = &T2b.b;
324*5c591343SA. Cody Schuffelen     TPM_RC                   retVal = TPM_RC_NO_RESULT;
325*5c591343SA. Cody Schuffelen     const ECC_CURVE_DATA    *C;
326*5c591343SA. Cody Schuffelen     bigConst                 order;
327*5c591343SA. Cody Schuffelen     bigConst                 prime;
328*5c591343SA. Cody Schuffelen     ECC_NUM(bnK);
329*5c591343SA. Cody Schuffelen     POINT(ecR);
330*5c591343SA. Cody Schuffelen //
331*5c591343SA. Cody Schuffelen     // Parameter checks
332*5c591343SA. Cody Schuffelen     if(E == NULL)
333*5c591343SA. Cody Schuffelen         ERROR_RETURN(TPM_RC_VALUE);
334*5c591343SA. Cody Schuffelen     C = AccessCurveData(E);
335*5c591343SA. Cody Schuffelen     order = CurveGetOrder(C);
336*5c591343SA. Cody Schuffelen     prime = CurveGetOrder(C);
337*5c591343SA. Cody Schuffelen 
338*5c591343SA. Cody Schuffelen     // If the digest does not produce a hash, then null the signature and return
339*5c591343SA. Cody Schuffelen     // a failure.
340*5c591343SA. Cody Schuffelen     if(digestSize == 0)
341*5c591343SA. Cody Schuffelen     {
342*5c591343SA. Cody Schuffelen         BnSetWord(bnR, 0);
343*5c591343SA. Cody Schuffelen         BnSetWord(bnS, 0);
344*5c591343SA. Cody Schuffelen         ERROR_RETURN(TPM_RC_SCHEME);
345*5c591343SA. Cody Schuffelen     }
346*5c591343SA. Cody Schuffelen     do
347*5c591343SA. Cody Schuffelen     {
348*5c591343SA. Cody Schuffelen         // Generate a random key pair
349*5c591343SA. Cody Schuffelen         if(!BnEccGenerateKeyPair(bnK, ecR, E, rand))
350*5c591343SA. Cody Schuffelen             break;
351*5c591343SA. Cody Schuffelen         // Convert R.x to a string
352*5c591343SA. Cody Schuffelen         BnTo2B(ecR->x, e, (NUMBYTES)BITS_TO_BYTES(BnSizeInBits(prime)));
353*5c591343SA. Cody Schuffelen 
354*5c591343SA. Cody Schuffelen         // f) compute r = Hash(e || P) (mod n)
355*5c591343SA. Cody Schuffelen         CryptHashStart(&hashState, hashAlg);
356*5c591343SA. Cody Schuffelen         CryptDigestUpdate2B(&hashState, e);
357*5c591343SA. Cody Schuffelen         CryptDigestUpdate2B(&hashState, &digest->b);
358*5c591343SA. Cody Schuffelen         e->size = CryptHashEnd(&hashState, digestSize, e->buffer);
359*5c591343SA. Cody Schuffelen         // Reduce the hash size if it is larger than the curve order
360*5c591343SA. Cody Schuffelen         SchnorrReduce(e, order);
361*5c591343SA. Cody Schuffelen         // Convert hash to number
362*5c591343SA. Cody Schuffelen         BnFrom2B(bnR, e);
363*5c591343SA. Cody Schuffelen         // Do the Schnorr computation
364*5c591343SA. Cody Schuffelen         retVal = BnSchnorrSign(bnS, bnK, bnR, bnD, CurveGetOrder(C));
365*5c591343SA. Cody Schuffelen     } while(retVal == TPM_RC_NO_RESULT);
366*5c591343SA. Cody Schuffelen Exit:
367*5c591343SA. Cody Schuffelen     return retVal;
368*5c591343SA. Cody Schuffelen }
369*5c591343SA. Cody Schuffelen 
370*5c591343SA. Cody Schuffelen #endif // ALG_ECSCHNORR
371*5c591343SA. Cody Schuffelen 
372*5c591343SA. Cody Schuffelen #if ALG_SM2
373*5c591343SA. Cody Schuffelen #ifdef  _SM2_SIGN_DEBUG
374*5c591343SA. Cody Schuffelen 
375*5c591343SA. Cody Schuffelen //*** BnHexEqual()
376*5c591343SA. Cody Schuffelen // This function compares a bignum value to a hex string.
377*5c591343SA. Cody Schuffelen //  Return Type: BOOL
378*5c591343SA. Cody Schuffelen //      TRUE(1)         values equal
379*5c591343SA. Cody Schuffelen //      FALSE(0)        values not equal
380*5c591343SA. Cody Schuffelen static BOOL
BnHexEqual(bigNum bn,const char * c)381*5c591343SA. Cody Schuffelen BnHexEqual(
382*5c591343SA. Cody Schuffelen     bigNum           bn,        //IN: big number value
383*5c591343SA. Cody Schuffelen     const char      *c          //IN: character string number
384*5c591343SA. Cody Schuffelen     )
385*5c591343SA. Cody Schuffelen {
386*5c591343SA. Cody Schuffelen     ECC_NUM(bnC);
387*5c591343SA. Cody Schuffelen     BnFromHex(bnC, c);
388*5c591343SA. Cody Schuffelen     return (BnUnsignedCmp(bn, bnC) == 0);
389*5c591343SA. Cody Schuffelen }
390*5c591343SA. Cody Schuffelen #endif // _SM2_SIGN_DEBUG
391*5c591343SA. Cody Schuffelen 
392*5c591343SA. Cody Schuffelen //*** BnSignEcSm2()
393*5c591343SA. Cody Schuffelen // This function signs a digest using the method defined in SM2 Part 2. The method
394*5c591343SA. Cody Schuffelen // in the standard will add a header to the message to be signed that is a hash of
395*5c591343SA. Cody Schuffelen // the values that define the key. This then hashed with the message to produce a
396*5c591343SA. Cody Schuffelen // digest ('e'). This function signs 'e'.
397*5c591343SA. Cody Schuffelen //  Return Type: TPM_RC
398*5c591343SA. Cody Schuffelen //      TPM_RC_VALUE         bad curve
399*5c591343SA. Cody Schuffelen static TPM_RC
BnSignEcSm2(bigNum bnR,bigNum bnS,bigCurve E,bigNum bnD,const TPM2B_DIGEST * digest,RAND_STATE * rand)400*5c591343SA. Cody Schuffelen BnSignEcSm2(
401*5c591343SA. Cody Schuffelen     bigNum                   bnR,       // OUT: 'r' component of the signature
402*5c591343SA. Cody Schuffelen     bigNum                   bnS,       // OUT: 's' component of the signature
403*5c591343SA. Cody Schuffelen     bigCurve                 E,         // IN: the curve used in signing
404*5c591343SA. Cody Schuffelen     bigNum                   bnD,       // IN: the private key
405*5c591343SA. Cody Schuffelen     const TPM2B_DIGEST      *digest,    // IN: the digest to sign
406*5c591343SA. Cody Schuffelen     RAND_STATE              *rand       // IN: random number generator (mostly for
407*5c591343SA. Cody Schuffelen                                         //     debug)
408*5c591343SA. Cody Schuffelen     )
409*5c591343SA. Cody Schuffelen {
410*5c591343SA. Cody Schuffelen     BN_MAX_INITIALIZED(bnE, digest);    // Don't know how big digest might be
411*5c591343SA. Cody Schuffelen     ECC_NUM(bnN);
412*5c591343SA. Cody Schuffelen     ECC_NUM(bnK);
413*5c591343SA. Cody Schuffelen     ECC_NUM(bnT);                       // temp
414*5c591343SA. Cody Schuffelen     POINT(Q1);
415*5c591343SA. Cody Schuffelen     bigConst                  order = (E != NULL)
416*5c591343SA. Cody Schuffelen         ? CurveGetOrder(AccessCurveData(E)) : NULL;
417*5c591343SA. Cody Schuffelen //
418*5c591343SA. Cody Schuffelen #ifdef _SM2_SIGN_DEBUG
419*5c591343SA. Cody Schuffelen     BnFromHex(bnE, "B524F552CD82B8B028476E005C377FB1"
420*5c591343SA. Cody Schuffelen                    "9A87E6FC682D48BB5D42E3D9B9EFFE76");
421*5c591343SA. Cody Schuffelen     BnFromHex(bnD, "128B2FA8BD433C6C068C8D803DFF7979"
422*5c591343SA. Cody Schuffelen                    "2A519A55171B1B650C23661D15897263");
423*5c591343SA. Cody Schuffelen #endif
424*5c591343SA. Cody Schuffelen     // A3: Use random number generator to generate random number 1 <= k <= n-1;
425*5c591343SA. Cody Schuffelen     // NOTE: Ax: numbers are from the SM2 standard
426*5c591343SA. Cody Schuffelen loop:
427*5c591343SA. Cody Schuffelen     {
428*5c591343SA. Cody Schuffelen         // Get a random number 0 < k < n
429*5c591343SA. Cody Schuffelen         BnGenerateRandomInRange(bnK, order, rand);
430*5c591343SA. Cody Schuffelen #ifdef _SM2_SIGN_DEBUG
431*5c591343SA. Cody Schuffelen         BnFromHex(bnK, "6CB28D99385C175C94F94E934817663F"
432*5c591343SA. Cody Schuffelen                        "C176D925DD72B727260DBAAE1FB2F96F");
433*5c591343SA. Cody Schuffelen #endif
434*5c591343SA. Cody Schuffelen         // A4: Figure out the point of elliptic curve (x1, y1)=[k]G, and according
435*5c591343SA. Cody Schuffelen         // to details specified in 4.2.7 in Part 1 of this document, transform the
436*5c591343SA. Cody Schuffelen         // data type of x1 into an integer;
437*5c591343SA. Cody Schuffelen         if(!BnEccModMult(Q1, NULL, bnK, E))
438*5c591343SA. Cody Schuffelen             goto loop;
439*5c591343SA. Cody Schuffelen         // A5: Figure out 'r' = ('e' + 'x1') mod 'n',
440*5c591343SA. Cody Schuffelen         BnAdd(bnR, bnE, Q1->x);
441*5c591343SA. Cody Schuffelen         BnMod(bnR, order);
442*5c591343SA. Cody Schuffelen #ifdef _SM2_SIGN_DEBUG
443*5c591343SA. Cody Schuffelen         pAssert(BnHexEqual(bnR, "40F1EC59F793D9F49E09DCEF49130D41"
444*5c591343SA. Cody Schuffelen                                 "94F79FB1EED2CAA55BACDB49C4E755D1"));
445*5c591343SA. Cody Schuffelen #endif
446*5c591343SA. Cody Schuffelen         // if r=0 or r+k=n, return to A3;
447*5c591343SA. Cody Schuffelen         if(BnEqualZero(bnR))
448*5c591343SA. Cody Schuffelen             goto loop;
449*5c591343SA. Cody Schuffelen         BnAdd(bnT, bnK, bnR);
450*5c591343SA. Cody Schuffelen         if(BnUnsignedCmp(bnT, bnN) == 0)
451*5c591343SA. Cody Schuffelen             goto loop;
452*5c591343SA. Cody Schuffelen         // A6: Figure out s = ((1 + dA)^-1  (k - r  dA)) mod n,
453*5c591343SA. Cody Schuffelen         // if s=0, return to A3;
454*5c591343SA. Cody Schuffelen         // compute t = (1+dA)^-1
455*5c591343SA. Cody Schuffelen         BnAddWord(bnT, bnD, 1);
456*5c591343SA. Cody Schuffelen         BnModInverse(bnT, bnT, order);
457*5c591343SA. Cody Schuffelen #ifdef _SM2_SIGN_DEBUG
458*5c591343SA. Cody Schuffelen         pAssert(BnHexEqual(bnT, "79BFCF3052C80DA7B939E0C6914A18CB"
459*5c591343SA. Cody Schuffelen                                 "B2D96D8555256E83122743A7D4F5F956"));
460*5c591343SA. Cody Schuffelen #endif
461*5c591343SA. Cody Schuffelen         // compute s = t * (k - r * dA) mod n
462*5c591343SA. Cody Schuffelen         BnModMult(bnS, bnR, bnD, order);
463*5c591343SA. Cody Schuffelen         // k - r * dA mod n = k + n - ((r * dA) mod n)
464*5c591343SA. Cody Schuffelen         BnSub(bnS, order, bnS);
465*5c591343SA. Cody Schuffelen         BnAdd(bnS, bnK, bnS);
466*5c591343SA. Cody Schuffelen         BnModMult(bnS, bnS, bnT, order);
467*5c591343SA. Cody Schuffelen #ifdef _SM2_SIGN_DEBUG
468*5c591343SA. Cody Schuffelen         pAssert(BnHexEqual(bnS, "6FC6DAC32C5D5CF10C77DFB20F7C2EB6"
469*5c591343SA. Cody Schuffelen                                 "67A457872FB09EC56327A67EC7DEEBE7"));
470*5c591343SA. Cody Schuffelen #endif
471*5c591343SA. Cody Schuffelen         if(BnEqualZero(bnS))
472*5c591343SA. Cody Schuffelen             goto loop;
473*5c591343SA. Cody Schuffelen     }
474*5c591343SA. Cody Schuffelen     // A7: According to details specified in 4.2.1 in Part 1 of this document,
475*5c591343SA. Cody Schuffelen     // transform the data type of r, s into bit strings, signature of message M
476*5c591343SA. Cody Schuffelen     // is (r, s).
477*5c591343SA. Cody Schuffelen     // This is handled by the common return code
478*5c591343SA. Cody Schuffelen #ifdef _SM2_SIGN_DEBUG
479*5c591343SA. Cody Schuffelen     pAssert(BnHexEqual(bnR, "40F1EC59F793D9F49E09DCEF49130D41"
480*5c591343SA. Cody Schuffelen                             "94F79FB1EED2CAA55BACDB49C4E755D1"));
481*5c591343SA. Cody Schuffelen     pAssert(BnHexEqual(bnS, "6FC6DAC32C5D5CF10C77DFB20F7C2EB6"
482*5c591343SA. Cody Schuffelen                             "67A457872FB09EC56327A67EC7DEEBE7"));
483*5c591343SA. Cody Schuffelen #endif
484*5c591343SA. Cody Schuffelen     return TPM_RC_SUCCESS;
485*5c591343SA. Cody Schuffelen }
486*5c591343SA. Cody Schuffelen #endif // ALG_SM2
487*5c591343SA. Cody Schuffelen 
488*5c591343SA. Cody Schuffelen //*** CryptEccSign()
489*5c591343SA. Cody Schuffelen // This function is the dispatch function for the various ECC-based
490*5c591343SA. Cody Schuffelen // signing schemes.
491*5c591343SA. Cody Schuffelen // There is a bit of ugliness to the parameter passing. In order to test this,
492*5c591343SA. Cody Schuffelen // we sometime would like to use a deterministic RNG so that we can get the same
493*5c591343SA. Cody Schuffelen // signatures during testing. The easiest way to do this for most schemes is to
494*5c591343SA. Cody Schuffelen // pass in a deterministic RNG and let it return canned values during testing.
495*5c591343SA. Cody Schuffelen // There is a competing need for a canned parameter to use in ECDAA. To accommodate
496*5c591343SA. Cody Schuffelen // both needs with minimal fuss, a special type of RAND_STATE is defined to carry
497*5c591343SA. Cody Schuffelen // the address of the commit value. The setup and handling of this is not very
498*5c591343SA. Cody Schuffelen // different for the caller than what was in previous versions of the code.
499*5c591343SA. Cody Schuffelen //  Return Type: TPM_RC
500*5c591343SA. Cody Schuffelen //      TPM_RC_SCHEME            'scheme' is not supported
501*5c591343SA. Cody Schuffelen LIB_EXPORT TPM_RC
CryptEccSign(TPMT_SIGNATURE * signature,OBJECT * signKey,const TPM2B_DIGEST * digest,TPMT_ECC_SCHEME * scheme,RAND_STATE * rand)502*5c591343SA. Cody Schuffelen CryptEccSign(
503*5c591343SA. Cody Schuffelen     TPMT_SIGNATURE          *signature,     // OUT: signature
504*5c591343SA. Cody Schuffelen     OBJECT                  *signKey,       // IN: ECC key to sign the hash
505*5c591343SA. Cody Schuffelen     const TPM2B_DIGEST      *digest,        // IN: digest to sign
506*5c591343SA. Cody Schuffelen     TPMT_ECC_SCHEME         *scheme,        // IN: signing scheme
507*5c591343SA. Cody Schuffelen     RAND_STATE              *rand
508*5c591343SA. Cody Schuffelen     )
509*5c591343SA. Cody Schuffelen {
510*5c591343SA. Cody Schuffelen     CURVE_INITIALIZED(E, signKey->publicArea.parameters.eccDetail.curveID);
511*5c591343SA. Cody Schuffelen     ECC_INITIALIZED(bnD, &signKey->sensitive.sensitive.ecc.b);
512*5c591343SA. Cody Schuffelen     ECC_NUM(bnR);
513*5c591343SA. Cody Schuffelen     ECC_NUM(bnS);
514*5c591343SA. Cody Schuffelen     const ECC_CURVE_DATA   *C;
515*5c591343SA. Cody Schuffelen     TPM_RC                  retVal = TPM_RC_SCHEME;
516*5c591343SA. Cody Schuffelen //
517*5c591343SA. Cody Schuffelen     NOT_REFERENCED(scheme);
518*5c591343SA. Cody Schuffelen     if(E == NULL)
519*5c591343SA. Cody Schuffelen         ERROR_RETURN(TPM_RC_VALUE);
520*5c591343SA. Cody Schuffelen      C = AccessCurveData(E);
521*5c591343SA. Cody Schuffelen     signature->signature.ecdaa.signatureR.t.size
522*5c591343SA. Cody Schuffelen         = sizeof(signature->signature.ecdaa.signatureR.t.buffer);
523*5c591343SA. Cody Schuffelen     signature->signature.ecdaa.signatureS.t.size
524*5c591343SA. Cody Schuffelen         = sizeof(signature->signature.ecdaa.signatureS.t.buffer);
525*5c591343SA. Cody Schuffelen     TEST(signature->sigAlg);
526*5c591343SA. Cody Schuffelen     switch(signature->sigAlg)
527*5c591343SA. Cody Schuffelen     {
528*5c591343SA. Cody Schuffelen         case TPM_ALG_ECDSA:
529*5c591343SA. Cody Schuffelen             retVal = BnSignEcdsa(bnR, bnS, E, bnD, digest, rand);
530*5c591343SA. Cody Schuffelen             break;
531*5c591343SA. Cody Schuffelen #if ALG_ECDAA
532*5c591343SA. Cody Schuffelen         case TPM_ALG_ECDAA:
533*5c591343SA. Cody Schuffelen             retVal = BnSignEcdaa(&signature->signature.ecdaa.signatureR, bnS, E,
534*5c591343SA. Cody Schuffelen                                  bnD, digest, scheme, signKey, rand);
535*5c591343SA. Cody Schuffelen             bnR = NULL;
536*5c591343SA. Cody Schuffelen             break;
537*5c591343SA. Cody Schuffelen #endif
538*5c591343SA. Cody Schuffelen #if ALG_ECSCHNORR
539*5c591343SA. Cody Schuffelen         case TPM_ALG_ECSCHNORR:
540*5c591343SA. Cody Schuffelen             retVal = BnSignEcSchnorr(bnR, bnS, E, bnD, digest,
541*5c591343SA. Cody Schuffelen                                      signature->signature.ecschnorr.hash,
542*5c591343SA. Cody Schuffelen                                      rand);
543*5c591343SA. Cody Schuffelen             break;
544*5c591343SA. Cody Schuffelen #endif
545*5c591343SA. Cody Schuffelen #if ALG_SM2
546*5c591343SA. Cody Schuffelen         case TPM_ALG_SM2:
547*5c591343SA. Cody Schuffelen             retVal = BnSignEcSm2(bnR, bnS, E, bnD, digest, rand);
548*5c591343SA. Cody Schuffelen             break;
549*5c591343SA. Cody Schuffelen #endif
550*5c591343SA. Cody Schuffelen         default:
551*5c591343SA. Cody Schuffelen             break;
552*5c591343SA. Cody Schuffelen     }
553*5c591343SA. Cody Schuffelen     // If signature generation worked, convert the results.
554*5c591343SA. Cody Schuffelen     if(retVal == TPM_RC_SUCCESS)
555*5c591343SA. Cody Schuffelen     {
556*5c591343SA. Cody Schuffelen         NUMBYTES     orderBytes =
557*5c591343SA. Cody Schuffelen             (NUMBYTES)BITS_TO_BYTES(BnSizeInBits(CurveGetOrder(C)));
558*5c591343SA. Cody Schuffelen         if(bnR != NULL)
559*5c591343SA. Cody Schuffelen             BnTo2B(bnR, &signature->signature.ecdaa.signatureR.b, orderBytes);
560*5c591343SA. Cody Schuffelen         if(bnS != NULL)
561*5c591343SA. Cody Schuffelen             BnTo2B(bnS, &signature->signature.ecdaa.signatureS.b, orderBytes);
562*5c591343SA. Cody Schuffelen     }
563*5c591343SA. Cody Schuffelen Exit:
564*5c591343SA. Cody Schuffelen     CURVE_FREE(E);
565*5c591343SA. Cody Schuffelen     return retVal;
566*5c591343SA. Cody Schuffelen }
567*5c591343SA. Cody Schuffelen 
568*5c591343SA. Cody Schuffelen //********************* Signature Validation   ********************
569*5c591343SA. Cody Schuffelen 
570*5c591343SA. Cody Schuffelen #if ALG_ECDSA
571*5c591343SA. Cody Schuffelen 
572*5c591343SA. Cody Schuffelen //*** BnValidateSignatureEcdsa()
573*5c591343SA. Cody Schuffelen // This function validates an ECDSA signature. rIn and sIn should have been checked
574*5c591343SA. Cody Schuffelen // to make sure that they are in the range 0 < 'v' < 'n'
575*5c591343SA. Cody Schuffelen //  Return Type: TPM_RC
576*5c591343SA. Cody Schuffelen //      TPM_RC_SIGNATURE           signature not valid
577*5c591343SA. Cody Schuffelen TPM_RC
BnValidateSignatureEcdsa(bigNum bnR,bigNum bnS,bigCurve E,bn_point_t * ecQ,const TPM2B_DIGEST * digest)578*5c591343SA. Cody Schuffelen BnValidateSignatureEcdsa(
579*5c591343SA. Cody Schuffelen     bigNum                   bnR,           // IN: 'r' component of the signature
580*5c591343SA. Cody Schuffelen     bigNum                   bnS,           // IN: 's' component of the signature
581*5c591343SA. Cody Schuffelen     bigCurve                 E,             // IN: the curve used in the signature
582*5c591343SA. Cody Schuffelen                                             //     process
583*5c591343SA. Cody Schuffelen     bn_point_t              *ecQ,           // IN: the public point of the key
584*5c591343SA. Cody Schuffelen     const TPM2B_DIGEST      *digest         // IN: the digest that was signed
585*5c591343SA. Cody Schuffelen     )
586*5c591343SA. Cody Schuffelen {
587*5c591343SA. Cody Schuffelen     // Make sure that the allocation for the digest is big enough for a maximum
588*5c591343SA. Cody Schuffelen     // digest
589*5c591343SA. Cody Schuffelen     BN_VAR(bnE, MAX(MAX_ECC_KEY_BYTES, MAX_DIGEST_SIZE) * 8);
590*5c591343SA. Cody Schuffelen     POINT(ecR);
591*5c591343SA. Cody Schuffelen     ECC_NUM(bnU1);
592*5c591343SA. Cody Schuffelen     ECC_NUM(bnU2);
593*5c591343SA. Cody Schuffelen     ECC_NUM(bnW);
594*5c591343SA. Cody Schuffelen     bigConst                 order = CurveGetOrder(AccessCurveData(E));
595*5c591343SA. Cody Schuffelen     TPM_RC                   retVal = TPM_RC_SIGNATURE;
596*5c591343SA. Cody Schuffelen //
597*5c591343SA. Cody Schuffelen     // Get adjusted digest
598*5c591343SA. Cody Schuffelen     EcdsaDigest(bnE, digest, order);
599*5c591343SA. Cody Schuffelen     // 1. If r and s are not both integers in the interval [1, n - 1], output
600*5c591343SA. Cody Schuffelen     //    INVALID.
601*5c591343SA. Cody Schuffelen     //  bnR  and bnS were validated by the caller
602*5c591343SA. Cody Schuffelen     // 2. Use the selected hash function to compute H0 = Hash(M0).
603*5c591343SA. Cody Schuffelen     // This is an input parameter
604*5c591343SA. Cody Schuffelen     // 3. Convert the bit string H0 to an integer e as described in Appendix B.2.
605*5c591343SA. Cody Schuffelen     // Done at entry
606*5c591343SA. Cody Schuffelen     // 4. Compute w = (s')^-1 mod n, using the routine in Appendix B.1.
607*5c591343SA. Cody Schuffelen     if(!BnModInverse(bnW, bnS, order))
608*5c591343SA. Cody Schuffelen         goto Exit;
609*5c591343SA. Cody Schuffelen     // 5. Compute u1 = (e' *   w) mod n, and compute u2 = (r' *  w) mod n.
610*5c591343SA. Cody Schuffelen     BnModMult(bnU1, bnE, bnW, order);
611*5c591343SA. Cody Schuffelen     BnModMult(bnU2, bnR, bnW, order);
612*5c591343SA. Cody Schuffelen     // 6. Compute the elliptic curve point R = (xR, yR) = u1G+u2Q, using EC
613*5c591343SA. Cody Schuffelen     //    scalar multiplication and EC addition (see [Routines]). If R is equal to
614*5c591343SA. Cody Schuffelen     //    the point at infinity O, output INVALID.
615*5c591343SA. Cody Schuffelen     if(BnPointMult(ecR, CurveGetG(AccessCurveData(E)), bnU1, ecQ, bnU2, E)
616*5c591343SA. Cody Schuffelen        != TPM_RC_SUCCESS)
617*5c591343SA. Cody Schuffelen         goto Exit;
618*5c591343SA. Cody Schuffelen     // 7. Compute v = Rx mod n.
619*5c591343SA. Cody Schuffelen     BnMod(ecR->x, order);
620*5c591343SA. Cody Schuffelen     // 8. Compare v and r0. If v = r0, output VALID; otherwise, output INVALID
621*5c591343SA. Cody Schuffelen     if(BnUnsignedCmp(ecR->x, bnR) != 0)
622*5c591343SA. Cody Schuffelen         goto Exit;
623*5c591343SA. Cody Schuffelen 
624*5c591343SA. Cody Schuffelen     retVal = TPM_RC_SUCCESS;
625*5c591343SA. Cody Schuffelen Exit:
626*5c591343SA. Cody Schuffelen     return retVal;
627*5c591343SA. Cody Schuffelen }
628*5c591343SA. Cody Schuffelen 
629*5c591343SA. Cody Schuffelen #endif      // ALG_ECDSA
630*5c591343SA. Cody Schuffelen 
631*5c591343SA. Cody Schuffelen #if ALG_SM2
632*5c591343SA. Cody Schuffelen 
633*5c591343SA. Cody Schuffelen //*** BnValidateSignatureEcSm2()
634*5c591343SA. Cody Schuffelen // This function is used to validate an SM2 signature.
635*5c591343SA. Cody Schuffelen //  Return Type: TPM_RC
636*5c591343SA. Cody Schuffelen //      TPM_RC_SIGNATURE            signature not valid
637*5c591343SA. Cody Schuffelen static TPM_RC
BnValidateSignatureEcSm2(bigNum bnR,bigNum bnS,bigCurve E,bigPoint ecQ,const TPM2B_DIGEST * digest)638*5c591343SA. Cody Schuffelen BnValidateSignatureEcSm2(
639*5c591343SA. Cody Schuffelen     bigNum                   bnR,       // IN: 'r' component of the signature
640*5c591343SA. Cody Schuffelen     bigNum                   bnS,       // IN: 's' component of the signature
641*5c591343SA. Cody Schuffelen     bigCurve                 E,         // IN: the curve used in the signature
642*5c591343SA. Cody Schuffelen                                         //     process
643*5c591343SA. Cody Schuffelen     bigPoint                 ecQ,       // IN: the public point of the key
644*5c591343SA. Cody Schuffelen     const TPM2B_DIGEST      *digest     // IN: the digest that was signed
645*5c591343SA. Cody Schuffelen     )
646*5c591343SA. Cody Schuffelen {
647*5c591343SA. Cody Schuffelen     POINT(P);
648*5c591343SA. Cody Schuffelen     ECC_NUM(bnRp);
649*5c591343SA. Cody Schuffelen     ECC_NUM(bnT);
650*5c591343SA. Cody Schuffelen     BN_MAX_INITIALIZED(bnE, digest);
651*5c591343SA. Cody Schuffelen     BOOL                     OK;
652*5c591343SA. Cody Schuffelen     bigConst                 order = CurveGetOrder(AccessCurveData(E));
653*5c591343SA. Cody Schuffelen 
654*5c591343SA. Cody Schuffelen #ifdef _SM2_SIGN_DEBUG
655*5c591343SA. Cody Schuffelen     // Make sure that the input signature is the test signature
656*5c591343SA. Cody Schuffelen     pAssert(BnHexEqual(bnR,
657*5c591343SA. Cody Schuffelen                        "40F1EC59F793D9F49E09DCEF49130D41"
658*5c591343SA. Cody Schuffelen                        "94F79FB1EED2CAA55BACDB49C4E755D1"));
659*5c591343SA. Cody Schuffelen     pAssert(BnHexEqual(bnS,
660*5c591343SA. Cody Schuffelen                        "6FC6DAC32C5D5CF10C77DFB20F7C2EB6"
661*5c591343SA. Cody Schuffelen                        "67A457872FB09EC56327A67EC7DEEBE7"));
662*5c591343SA. Cody Schuffelen #endif
663*5c591343SA. Cody Schuffelen     // b)   compute t  := (r + s) mod n
664*5c591343SA. Cody Schuffelen     BnAdd(bnT, bnR, bnS);
665*5c591343SA. Cody Schuffelen     BnMod(bnT, order);
666*5c591343SA. Cody Schuffelen #ifdef _SM2_SIGN_DEBUG
667*5c591343SA. Cody Schuffelen     pAssert(BnHexEqual(bnT,
668*5c591343SA. Cody Schuffelen                        "2B75F07ED7ECE7CCC1C8986B991F441A"
669*5c591343SA. Cody Schuffelen                        "D324D6D619FE06DD63ED32E0C997C801"));
670*5c591343SA. Cody Schuffelen #endif
671*5c591343SA. Cody Schuffelen     // c)   verify that t > 0
672*5c591343SA. Cody Schuffelen     OK = !BnEqualZero(bnT);
673*5c591343SA. Cody Schuffelen     if(!OK)
674*5c591343SA. Cody Schuffelen         // set T to a value that should allow rest of the computations to run
675*5c591343SA. Cody Schuffelen         // without trouble
676*5c591343SA. Cody Schuffelen         BnCopy(bnT, bnS);
677*5c591343SA. Cody Schuffelen     // d)   compute (x, y) := [s]G + [t]Q
678*5c591343SA. Cody Schuffelen     OK = BnEccModMult2(P, NULL, bnS, ecQ, bnT, E);
679*5c591343SA. Cody Schuffelen #ifdef  _SM2_SIGN_DEBUG
680*5c591343SA. Cody Schuffelen     pAssert(OK && BnHexEqual(P->x,
681*5c591343SA. Cody Schuffelen                              "110FCDA57615705D5E7B9324AC4B856D"
682*5c591343SA. Cody Schuffelen                              "23E6D9188B2AE47759514657CE25D112"));
683*5c591343SA. Cody Schuffelen #endif
684*5c591343SA. Cody Schuffelen     // e)   compute r' := (e + x) mod n (the x coordinate is in bnT)
685*5c591343SA. Cody Schuffelen     OK = OK && BnAdd(bnRp, bnE, P->x);
686*5c591343SA. Cody Schuffelen     OK = OK && BnMod(bnRp, order);
687*5c591343SA. Cody Schuffelen 
688*5c591343SA. Cody Schuffelen     // f)   verify that r' = r
689*5c591343SA. Cody Schuffelen     OK = OK && (BnUnsignedCmp(bnR, bnRp) == 0);
690*5c591343SA. Cody Schuffelen 
691*5c591343SA. Cody Schuffelen     if(!OK)
692*5c591343SA. Cody Schuffelen         return TPM_RC_SIGNATURE;
693*5c591343SA. Cody Schuffelen     else
694*5c591343SA. Cody Schuffelen         return TPM_RC_SUCCESS;
695*5c591343SA. Cody Schuffelen }
696*5c591343SA. Cody Schuffelen 
697*5c591343SA. Cody Schuffelen #endif  // ALG_SM2
698*5c591343SA. Cody Schuffelen 
699*5c591343SA. Cody Schuffelen #if ALG_ECSCHNORR
700*5c591343SA. Cody Schuffelen 
701*5c591343SA. Cody Schuffelen //*** BnValidateSignatureEcSchnorr()
702*5c591343SA. Cody Schuffelen // This function is used to validate an EC Schnorr signature.
703*5c591343SA. Cody Schuffelen //  Return Type: TPM_RC
704*5c591343SA. Cody Schuffelen //      TPM_RC_SIGNATURE        signature not valid
705*5c591343SA. Cody Schuffelen static TPM_RC
BnValidateSignatureEcSchnorr(bigNum bnR,bigNum bnS,TPM_ALG_ID hashAlg,bigCurve E,bigPoint ecQ,const TPM2B_DIGEST * digest)706*5c591343SA. Cody Schuffelen BnValidateSignatureEcSchnorr(
707*5c591343SA. Cody Schuffelen     bigNum               bnR,       // IN: 'r' component of the signature
708*5c591343SA. Cody Schuffelen     bigNum               bnS,       // IN: 's' component of the signature
709*5c591343SA. Cody Schuffelen     TPM_ALG_ID           hashAlg,   // IN: hash algorithm of the signature
710*5c591343SA. Cody Schuffelen     bigCurve             E,         // IN: the curve used in the signature
711*5c591343SA. Cody Schuffelen                                     //     process
712*5c591343SA. Cody Schuffelen     bigPoint             ecQ,       // IN: the public point of the key
713*5c591343SA. Cody Schuffelen     const TPM2B_DIGEST  *digest     // IN: the digest that was signed
714*5c591343SA. Cody Schuffelen     )
715*5c591343SA. Cody Schuffelen {
716*5c591343SA. Cody Schuffelen     BN_MAX(bnRn);
717*5c591343SA. Cody Schuffelen     POINT(ecE);
718*5c591343SA. Cody Schuffelen     BN_MAX(bnEx);
719*5c591343SA. Cody Schuffelen     const ECC_CURVE_DATA    *C = AccessCurveData(E);
720*5c591343SA. Cody Schuffelen     bigConst                 order = CurveGetOrder(C);
721*5c591343SA. Cody Schuffelen     UINT16                   digestSize = CryptHashGetDigestSize(hashAlg);
722*5c591343SA. Cody Schuffelen     HASH_STATE               hashState;
723*5c591343SA. Cody Schuffelen     TPM2B_TYPE(BUFFER, MAX(MAX_ECC_PARAMETER_BYTES, MAX_DIGEST_SIZE));
724*5c591343SA. Cody Schuffelen     TPM2B_BUFFER             Ex2 = {{sizeof(Ex2.t.buffer),{ 0 }}};
725*5c591343SA. Cody Schuffelen     BOOL                     OK;
726*5c591343SA. Cody Schuffelen //
727*5c591343SA. Cody Schuffelen     // E = [s]G - [r]Q
728*5c591343SA. Cody Schuffelen     BnMod(bnR, order);
729*5c591343SA. Cody Schuffelen     // Make -r = n - r
730*5c591343SA. Cody Schuffelen     BnSub(bnRn, order, bnR);
731*5c591343SA. Cody Schuffelen     // E = [s]G + [-r]Q
732*5c591343SA. Cody Schuffelen     OK = BnPointMult(ecE, CurveGetG(C), bnS, ecQ, bnRn, E) == TPM_RC_SUCCESS;
733*5c591343SA. Cody Schuffelen //   // reduce the x portion of E mod q
734*5c591343SA. Cody Schuffelen //    OK = OK && BnMod(ecE->x, order);
735*5c591343SA. Cody Schuffelen     // Convert to byte string
736*5c591343SA. Cody Schuffelen     OK = OK && BnTo2B(ecE->x, &Ex2.b,
737*5c591343SA. Cody Schuffelen                       (NUMBYTES)(BITS_TO_BYTES(BnSizeInBits(order))));
738*5c591343SA. Cody Schuffelen     if(OK)
739*5c591343SA. Cody Schuffelen     {
740*5c591343SA. Cody Schuffelen // Ex = h(pE.x || digest)
741*5c591343SA. Cody Schuffelen         CryptHashStart(&hashState, hashAlg);
742*5c591343SA. Cody Schuffelen         CryptDigestUpdate(&hashState, Ex2.t.size, Ex2.t.buffer);
743*5c591343SA. Cody Schuffelen         CryptDigestUpdate(&hashState, digest->t.size, digest->t.buffer);
744*5c591343SA. Cody Schuffelen         Ex2.t.size = CryptHashEnd(&hashState, digestSize, Ex2.t.buffer);
745*5c591343SA. Cody Schuffelen         SchnorrReduce(&Ex2.b, order);
746*5c591343SA. Cody Schuffelen         BnFrom2B(bnEx, &Ex2.b);
747*5c591343SA. Cody Schuffelen         // see if Ex matches R
748*5c591343SA. Cody Schuffelen         OK = BnUnsignedCmp(bnEx, bnR) == 0;
749*5c591343SA. Cody Schuffelen     }
750*5c591343SA. Cody Schuffelen     return (OK) ? TPM_RC_SUCCESS : TPM_RC_SIGNATURE;
751*5c591343SA. Cody Schuffelen }
752*5c591343SA. Cody Schuffelen #endif  // ALG_ECSCHNORR
753*5c591343SA. Cody Schuffelen 
754*5c591343SA. Cody Schuffelen //*** CryptEccValidateSignature()
755*5c591343SA. Cody Schuffelen // This function validates an EcDsa or EcSchnorr signature.
756*5c591343SA. Cody Schuffelen // The point 'Qin' needs to have been validated to be on the curve of 'curveId'.
757*5c591343SA. Cody Schuffelen //  Return Type: TPM_RC
758*5c591343SA. Cody Schuffelen //      TPM_RC_SIGNATURE            not a valid signature
759*5c591343SA. Cody Schuffelen LIB_EXPORT TPM_RC
CryptEccValidateSignature(TPMT_SIGNATURE * signature,OBJECT * signKey,const TPM2B_DIGEST * digest)760*5c591343SA. Cody Schuffelen CryptEccValidateSignature(
761*5c591343SA. Cody Schuffelen     TPMT_SIGNATURE          *signature,     // IN: signature to be verified
762*5c591343SA. Cody Schuffelen     OBJECT                  *signKey,       // IN: ECC key signed the hash
763*5c591343SA. Cody Schuffelen     const TPM2B_DIGEST      *digest         // IN: digest that was signed
764*5c591343SA. Cody Schuffelen     )
765*5c591343SA. Cody Schuffelen {
766*5c591343SA. Cody Schuffelen     CURVE_INITIALIZED(E, signKey->publicArea.parameters.eccDetail.curveID);
767*5c591343SA. Cody Schuffelen     ECC_NUM(bnR);
768*5c591343SA. Cody Schuffelen     ECC_NUM(bnS);
769*5c591343SA. Cody Schuffelen     POINT_INITIALIZED(ecQ, &signKey->publicArea.unique.ecc);
770*5c591343SA. Cody Schuffelen     bigConst                 order;
771*5c591343SA. Cody Schuffelen     TPM_RC                   retVal;
772*5c591343SA. Cody Schuffelen 
773*5c591343SA. Cody Schuffelen     if(E == NULL)
774*5c591343SA. Cody Schuffelen         ERROR_RETURN(TPM_RC_VALUE);
775*5c591343SA. Cody Schuffelen 
776*5c591343SA. Cody Schuffelen     order = CurveGetOrder(AccessCurveData(E));
777*5c591343SA. Cody Schuffelen 
778*5c591343SA. Cody Schuffelen //    // Make sure that the scheme is valid
779*5c591343SA. Cody Schuffelen     switch(signature->sigAlg)
780*5c591343SA. Cody Schuffelen     {
781*5c591343SA. Cody Schuffelen         case TPM_ALG_ECDSA:
782*5c591343SA. Cody Schuffelen #if ALG_ECSCHNORR
783*5c591343SA. Cody Schuffelen         case TPM_ALG_ECSCHNORR:
784*5c591343SA. Cody Schuffelen #endif
785*5c591343SA. Cody Schuffelen #if ALG_SM2
786*5c591343SA. Cody Schuffelen         case TPM_ALG_SM2:
787*5c591343SA. Cody Schuffelen #endif
788*5c591343SA. Cody Schuffelen             break;
789*5c591343SA. Cody Schuffelen         default:
790*5c591343SA. Cody Schuffelen             ERROR_RETURN(TPM_RC_SCHEME);
791*5c591343SA. Cody Schuffelen             break;
792*5c591343SA. Cody Schuffelen     }
793*5c591343SA. Cody Schuffelen     // Can convert r and s after determining that the scheme is an ECC scheme. If
794*5c591343SA. Cody Schuffelen     // this conversion doesn't work, it means that the unmarshaling code for
795*5c591343SA. Cody Schuffelen     // an ECC signature is broken.
796*5c591343SA. Cody Schuffelen     BnFrom2B(bnR, &signature->signature.ecdsa.signatureR.b);
797*5c591343SA. Cody Schuffelen     BnFrom2B(bnS, &signature->signature.ecdsa.signatureS.b);
798*5c591343SA. Cody Schuffelen 
799*5c591343SA. Cody Schuffelen     // r and s have to be greater than 0 but less than the curve order
800*5c591343SA. Cody Schuffelen     if(BnEqualZero(bnR) || BnEqualZero(bnS))
801*5c591343SA. Cody Schuffelen         ERROR_RETURN(TPM_RC_SIGNATURE);
802*5c591343SA. Cody Schuffelen     if((BnUnsignedCmp(bnS, order) >= 0)
803*5c591343SA. Cody Schuffelen        || (BnUnsignedCmp(bnR, order) >= 0))
804*5c591343SA. Cody Schuffelen         ERROR_RETURN(TPM_RC_SIGNATURE);
805*5c591343SA. Cody Schuffelen 
806*5c591343SA. Cody Schuffelen     switch(signature->sigAlg)
807*5c591343SA. Cody Schuffelen     {
808*5c591343SA. Cody Schuffelen         case TPM_ALG_ECDSA:
809*5c591343SA. Cody Schuffelen             retVal = BnValidateSignatureEcdsa(bnR, bnS, E, ecQ, digest);
810*5c591343SA. Cody Schuffelen             break;
811*5c591343SA. Cody Schuffelen 
812*5c591343SA. Cody Schuffelen #if ALG_ECSCHNORR
813*5c591343SA. Cody Schuffelen         case TPM_ALG_ECSCHNORR:
814*5c591343SA. Cody Schuffelen             retVal = BnValidateSignatureEcSchnorr(bnR, bnS,
815*5c591343SA. Cody Schuffelen                                                   signature->signature.any.hashAlg,
816*5c591343SA. Cody Schuffelen                                                   E, ecQ, digest);
817*5c591343SA. Cody Schuffelen             break;
818*5c591343SA. Cody Schuffelen #endif
819*5c591343SA. Cody Schuffelen #if ALG_SM2
820*5c591343SA. Cody Schuffelen         case TPM_ALG_SM2:
821*5c591343SA. Cody Schuffelen             retVal = BnValidateSignatureEcSm2(bnR, bnS, E, ecQ, digest);
822*5c591343SA. Cody Schuffelen             break;
823*5c591343SA. Cody Schuffelen #endif
824*5c591343SA. Cody Schuffelen         default:
825*5c591343SA. Cody Schuffelen             FAIL(FATAL_ERROR_INTERNAL);
826*5c591343SA. Cody Schuffelen     }
827*5c591343SA. Cody Schuffelen Exit:
828*5c591343SA. Cody Schuffelen     CURVE_FREE(E);
829*5c591343SA. Cody Schuffelen     return retVal;
830*5c591343SA. Cody Schuffelen }
831*5c591343SA. Cody Schuffelen 
832*5c591343SA. Cody Schuffelen //***CryptEccCommitCompute()
833*5c591343SA. Cody Schuffelen // This function performs the point multiply operations required by TPM2_Commit.
834*5c591343SA. Cody Schuffelen //
835*5c591343SA. Cody Schuffelen // If 'B' or 'M' is provided, they must be on the curve defined by 'curveId'. This
836*5c591343SA. Cody Schuffelen // routine does not check that they are on the curve and results are unpredictable
837*5c591343SA. Cody Schuffelen // if they are not.
838*5c591343SA. Cody Schuffelen //
839*5c591343SA. Cody Schuffelen // It is a fatal error if 'r' is NULL. If 'B' is not NULL, then it is a
840*5c591343SA. Cody Schuffelen // fatal error if 'd' is NULL or if 'K' and 'L' are both NULL.
841*5c591343SA. Cody Schuffelen // If 'M' is not NULL, then it is a fatal error if 'E' is NULL.
842*5c591343SA. Cody Schuffelen //
843*5c591343SA. Cody Schuffelen //  Return Type: TPM_RC
844*5c591343SA. Cody Schuffelen //      TPM_RC_NO_RESULT        if 'K', 'L' or 'E' was computed to be the point
845*5c591343SA. Cody Schuffelen //                              at infinity
846*5c591343SA. Cody Schuffelen //      TPM_RC_CANCELED         a cancel indication was asserted during this
847*5c591343SA. Cody Schuffelen //                              function
848*5c591343SA. Cody Schuffelen LIB_EXPORT TPM_RC
CryptEccCommitCompute(TPMS_ECC_POINT * K,TPMS_ECC_POINT * L,TPMS_ECC_POINT * E,TPM_ECC_CURVE curveId,TPMS_ECC_POINT * M,TPMS_ECC_POINT * B,TPM2B_ECC_PARAMETER * d,TPM2B_ECC_PARAMETER * r)849*5c591343SA. Cody Schuffelen CryptEccCommitCompute(
850*5c591343SA. Cody Schuffelen     TPMS_ECC_POINT          *K,             // OUT: [d]B or [r]Q
851*5c591343SA. Cody Schuffelen     TPMS_ECC_POINT          *L,             // OUT: [r]B
852*5c591343SA. Cody Schuffelen     TPMS_ECC_POINT          *E,             // OUT: [r]M
853*5c591343SA. Cody Schuffelen     TPM_ECC_CURVE            curveId,       // IN: the curve for the computations
854*5c591343SA. Cody Schuffelen     TPMS_ECC_POINT          *M,             // IN: M (optional)
855*5c591343SA. Cody Schuffelen     TPMS_ECC_POINT          *B,             // IN: B (optional)
856*5c591343SA. Cody Schuffelen     TPM2B_ECC_PARAMETER     *d,             // IN: d (optional)
857*5c591343SA. Cody Schuffelen     TPM2B_ECC_PARAMETER     *r              // IN: the computed r value (required)
858*5c591343SA. Cody Schuffelen     )
859*5c591343SA. Cody Schuffelen {
860*5c591343SA. Cody Schuffelen     CURVE_INITIALIZED(curve, curveId);  // Normally initialize E as the curve, but
861*5c591343SA. Cody Schuffelen                                         // E means something else in this function
862*5c591343SA. Cody Schuffelen     ECC_INITIALIZED(bnR, r);
863*5c591343SA. Cody Schuffelen     TPM_RC               retVal = TPM_RC_SUCCESS;
864*5c591343SA. Cody Schuffelen //
865*5c591343SA. Cody Schuffelen     // Validate that the required parameters are provided.
866*5c591343SA. Cody Schuffelen     // Note: E has to be provided if computing E := [r]Q or E := [r]M. Will do
867*5c591343SA. Cody Schuffelen     // E := [r]Q if both M and B are NULL.
868*5c591343SA. Cody Schuffelen     pAssert(r != NULL && E != NULL);
869*5c591343SA. Cody Schuffelen 
870*5c591343SA. Cody Schuffelen     // Initialize the output points in case they are not computed
871*5c591343SA. Cody Schuffelen     ClearPoint2B(K);
872*5c591343SA. Cody Schuffelen     ClearPoint2B(L);
873*5c591343SA. Cody Schuffelen     ClearPoint2B(E);
874*5c591343SA. Cody Schuffelen 
875*5c591343SA. Cody Schuffelen     // Sizes of the r parameter may not be zero
876*5c591343SA. Cody Schuffelen     pAssert(r->t.size > 0);
877*5c591343SA. Cody Schuffelen 
878*5c591343SA. Cody Schuffelen     // If B is provided, compute K=[d]B and L=[r]B
879*5c591343SA. Cody Schuffelen     if(B != NULL)
880*5c591343SA. Cody Schuffelen     {
881*5c591343SA. Cody Schuffelen         ECC_INITIALIZED(bnD, d);
882*5c591343SA. Cody Schuffelen         POINT_INITIALIZED(pB, B);
883*5c591343SA. Cody Schuffelen         POINT(pK);
884*5c591343SA. Cody Schuffelen         POINT(pL);
885*5c591343SA. Cody Schuffelen //
886*5c591343SA. Cody Schuffelen         pAssert(d != NULL && K != NULL && L != NULL);
887*5c591343SA. Cody Schuffelen 
888*5c591343SA. Cody Schuffelen         if(!BnIsOnCurve(pB, AccessCurveData(curve)))
889*5c591343SA. Cody Schuffelen             ERROR_RETURN(TPM_RC_VALUE);
890*5c591343SA. Cody Schuffelen          // do the math for K = [d]B
891*5c591343SA. Cody Schuffelen         if((retVal = BnPointMult(pK, pB, bnD, NULL, NULL, curve)) != TPM_RC_SUCCESS)
892*5c591343SA. Cody Schuffelen             goto Exit;
893*5c591343SA. Cody Schuffelen         // Convert BN K to TPM2B K
894*5c591343SA. Cody Schuffelen         BnPointTo2B(K, pK, curve);
895*5c591343SA. Cody Schuffelen         //  compute L= [r]B after checking for cancel
896*5c591343SA. Cody Schuffelen         if(_plat__IsCanceled())
897*5c591343SA. Cody Schuffelen             ERROR_RETURN(TPM_RC_CANCELED);
898*5c591343SA. Cody Schuffelen         // compute L = [r]B
899*5c591343SA. Cody Schuffelen         if(!BnIsValidPrivateEcc(bnR, curve))
900*5c591343SA. Cody Schuffelen             ERROR_RETURN(TPM_RC_VALUE);
901*5c591343SA. Cody Schuffelen         if((retVal = BnPointMult(pL, pB, bnR, NULL, NULL, curve)) != TPM_RC_SUCCESS)
902*5c591343SA. Cody Schuffelen             goto Exit;
903*5c591343SA. Cody Schuffelen         // Convert BN L to TPM2B L
904*5c591343SA. Cody Schuffelen         BnPointTo2B(L, pL, curve);
905*5c591343SA. Cody Schuffelen     }
906*5c591343SA. Cody Schuffelen     if((M != NULL) || (B == NULL))
907*5c591343SA. Cody Schuffelen     {
908*5c591343SA. Cody Schuffelen         POINT_INITIALIZED(pM, M);
909*5c591343SA. Cody Schuffelen         POINT(pE);
910*5c591343SA. Cody Schuffelen //
911*5c591343SA. Cody Schuffelen         // Make sure that a place was provided for the result
912*5c591343SA. Cody Schuffelen         pAssert(E != NULL);
913*5c591343SA. Cody Schuffelen 
914*5c591343SA. Cody Schuffelen         // if this is the third point multiply, check for cancel first
915*5c591343SA. Cody Schuffelen         if((B != NULL) && _plat__IsCanceled())
916*5c591343SA. Cody Schuffelen             ERROR_RETURN(TPM_RC_CANCELED);
917*5c591343SA. Cody Schuffelen 
918*5c591343SA. Cody Schuffelen         // If M provided, then pM will not be NULL and will compute E = [r]M.
919*5c591343SA. Cody Schuffelen         // However, if M was not provided, then pM will be NULL and E = [r]G
920*5c591343SA. Cody Schuffelen         // will be computed
921*5c591343SA. Cody Schuffelen         if((retVal = BnPointMult(pE, pM, bnR, NULL, NULL, curve)) != TPM_RC_SUCCESS)
922*5c591343SA. Cody Schuffelen             goto Exit;
923*5c591343SA. Cody Schuffelen         // Convert E to 2B format
924*5c591343SA. Cody Schuffelen         BnPointTo2B(E, pE, curve);
925*5c591343SA. Cody Schuffelen     }
926*5c591343SA. Cody Schuffelen Exit:
927*5c591343SA. Cody Schuffelen     CURVE_FREE(curve);
928*5c591343SA. Cody Schuffelen     return retVal;
929*5c591343SA. Cody Schuffelen }
930*5c591343SA. Cody Schuffelen 
931*5c591343SA. Cody Schuffelen #endif  // ALG_ECC