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