1 // This file was extracted from the TCG Published
2 // Trusted Platform Module Library
3 // Part 3: Commands
4 // Family "2.0"
5 // Level 00 Revision 01.16
6 // October 30, 2014
7 
8 #include "InternalRoutines.h"
9 #include "Commit_fp.h"
10 #ifdef TPM_ALG_ECC
11 //
12 //
13 //     Error Returns                     Meaning
14 //
15 //     TPM_RC_ATTRIBUTES                 keyHandle references a restricted key that is not a signing key
16 //     TPM_RC_ECC_POINT                  either P1 or the point derived from s2 is not on the curve of
17 //                                       keyHandle
18 //     TPM_RC_HASH                       invalid name algorithm in keyHandle
19 //     TPM_RC_KEY                        keyHandle does not reference an ECC key
20 //     TPM_RC_SCHEME                     the scheme of keyHandle is not an anonymous scheme
21 //     TPM_RC_NO_RESULT                  K, L or E was a point at infinity; or failed to generate r value
22 //     TPM_RC_SIZE                       s2 is empty but y2 is not or s2 provided but y2 is not
23 //
24 TPM_RC
TPM2_Commit(Commit_In * in,Commit_Out * out)25 TPM2_Commit(
26    Commit_In         *in,                 // IN: input parameter list
27    Commit_Out        *out                 // OUT: output parameter list
28    )
29 {
30    OBJECT                    *eccKey;
31    TPMS_ECC_POINT             P2;
32    TPMS_ECC_POINT            *pP2 = NULL;
33    TPMS_ECC_POINT            *pP1 = NULL;
34    TPM2B_ECC_PARAMETER        r;
35    TPM2B                     *p;
36    TPM_RC                     result;
37    TPMS_ECC_PARMS            *parms;
38 
39 // Input Validation
40 
41    eccKey = ObjectGet(in->signHandle);
42    parms = & eccKey->publicArea.parameters.eccDetail;
43 
44    // Input key must be an ECC key
45    if(eccKey->publicArea.type != TPM_ALG_ECC)
46        return TPM_RC_KEY + RC_Commit_signHandle;
47 
48     // This command may only be used with a sign-only key using an anonymous
49     // scheme.
50     // NOTE: a sign + decrypt key has no scheme so it will not be an anonymous one
51     // and an unrestricted sign key might no have a signing scheme but it can't
52     // be use in Commit()
53    if(!CryptIsSchemeAnonymous(parms->scheme.scheme))
54             return TPM_RC_SCHEME + RC_Commit_signHandle;
55 
56    // Make sure that both parts of P2 are present if either is present
57    if((in->s2.t.size == 0) != (in->y2.t.size == 0))
58        return TPM_RC_SIZE + RC_Commit_y2;
59 
60    // Get prime modulus for the curve. This is needed later but getting this now
61    // allows confirmation that the curve exists
62    p = (TPM2B *)CryptEccGetParameter('p', parms->curveID);
63 
64    // if no p, then the curve ID is bad
65 //
66   // NOTE: This should never occur if the input unmarshaling code is working
67   // correctly
68   pAssert(p != NULL);
69 
70   // Get the random value that will be used in the point multiplications
71   // Note: this does not commit the count.
72   if(!CryptGenerateR(&r, NULL, parms->curveID, &eccKey->name))
73       return TPM_RC_NO_RESULT;
74 
75   // Set up P2 if s2 and Y2 are provided
76   if(in->s2.t.size != 0)
77   {
78       pP2 = &P2;
79 
80       // copy y2 for P2
81       MemoryCopy2B(&P2.y.b, &in->y2.b, sizeof(P2.y.t.buffer));
82       // Compute x2 HnameAlg(s2) mod p
83 
84       //      do the hash operation on s2 with the size of curve 'p'
85       P2.x.t.size = CryptHashBlock(eccKey->publicArea.nameAlg,
86                                    in->s2.t.size,
87                                    in->s2.t.buffer,
88                                    p->size,
89                                    P2.x.t.buffer);
90 
91       // If there were error returns in the hash routine, indicate a problem
92       // with the hash in
93       if(P2.x.t.size == 0)
94           return TPM_RC_HASH + RC_Commit_signHandle;
95 
96       // set p2.x = hash(s2) mod p
97       if(CryptDivide(&P2.x.b, p, NULL, &P2.x.b) != TPM_RC_SUCCESS)
98           return TPM_RC_NO_RESULT;
99 
100       if(!CryptEccIsPointOnCurve(parms->curveID, pP2))
101           return TPM_RC_ECC_POINT + RC_Commit_s2;
102 
103       if(eccKey->attributes.publicOnly == SET)
104           return TPM_RC_KEY + RC_Commit_signHandle;
105 
106   }
107   // If there is a P1, make sure that it is on the curve
108   // NOTE: an "empty" point has two UINT16 values which are the size values
109   // for each of the coordinates.
110   if(in->P1.t.size > 4)
111   {
112       pP1 = &in->P1.t.point;
113       if(!CryptEccIsPointOnCurve(parms->curveID, pP1))
114           return TPM_RC_ECC_POINT + RC_Commit_P1;
115   }
116 
117   // Pass the parameters to CryptCommit.
118   // The work is not done in-line because it does several point multiplies
119   // with the same curve. There is significant optimization by not
120   // having to reload the curve parameters multiple times.
121   result = CryptCommitCompute(&out->K.t.point,
122                               &out->L.t.point,
123                               &out->E.t.point,
124                               parms->curveID,
125                               pP1,
126                               pP2,
127                               &eccKey->sensitive.sensitive.ecc,
128                               &r);
129   if(result != TPM_RC_SUCCESS)
130       return result;
131 
132    out->K.t.size = TPMS_ECC_POINT_Marshal(&out->K.t.point, NULL, NULL);
133    out->L.t.size = TPMS_ECC_POINT_Marshal(&out->L.t.point, NULL, NULL);
134    out->E.t.size = TPMS_ECC_POINT_Marshal(&out->E.t.point, NULL, NULL);
135 
136    // The commit computation was successful so complete the commit by setting
137    // the bit
138    out->counter = CryptCommit();
139 
140    return TPM_RC_SUCCESS;
141 }
142 #endif
143