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