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