/*############################################################################ # Copyright 2017 Intel Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. ############################################################################*/ /// Sensitive pre-computed signature implementation /*! \file */ #include #include #include "epid/common/math/ecgroup.h" #include "epid/common/math/finitefield.h" #include "epid/common/src/endian_convert.h" #include "epid/common/src/epid2params.h" #include "epid/common/src/memory.h" #include "epid/common/src/stack.h" #include "epid/member/src/context.h" #include "epid/member/tpm2/commit.h" #include "epid/member/tpm2/context.h" #include "epid/member/tpm2/getrandom.h" #include "epid/member/tpm2/sign.h" /// Handle SDK Error with Break #define BREAK_ON_EPID_ERROR(ret) \ if (kEpidNoErr != (ret)) { \ break; \ } /// Count of elements in array #define COUNT_OF(A) (sizeof(A) / sizeof((A)[0])) static EpidStatus MemberComputePreSig(MemberCtx const* ctx, PreComputedSignature* precompsig); EpidStatus EpidAddPreSigs(MemberCtx* ctx, size_t number_presigs) { PreComputedSignature* new_presigs = NULL; size_t i = 0; if (!ctx || !ctx->presigs) return kEpidBadArgErr; if (0 == number_presigs) return kEpidNoErr; new_presigs = (PreComputedSignature*)StackPushN(ctx->presigs, number_presigs, NULL); if (!new_presigs) return kEpidMemAllocErr; for (i = 0; i < number_presigs; i++) { EpidStatus sts = MemberComputePreSig(ctx, &new_presigs[i]); if (kEpidNoErr != sts) { // roll back pre-computed-signature pool StackPopN(ctx->presigs, number_presigs, 0); return sts; } } return kEpidNoErr; } size_t EpidGetNumPreSigs(MemberCtx const* ctx) { return (ctx && ctx->presigs) ? StackGetSize(ctx->presigs) : (size_t)0; } EpidStatus MemberGetPreSig(MemberCtx* ctx, PreComputedSignature* presig) { if (!ctx || !presig) { return kEpidBadArgErr; } if (StackGetSize(ctx->presigs)) { // Use existing pre-computed signature if (!StackPopN(ctx->presigs, 1, presig)) { return kEpidErr; } return kEpidNoErr; } // generate a new pre-computed signature return MemberComputePreSig(ctx, presig); } /// Performs Pre-computation that can be used to speed up signing EpidStatus MemberComputePreSig(MemberCtx const* ctx, PreComputedSignature* precompsig) { EpidStatus sts = kEpidErr; EcPoint* B = NULL; EcPoint* k = NULL; EcPoint* t = NULL; // temporary, used for K, T, R1 EcPoint* e = NULL; FfElement* R2 = NULL; FfElement* a = NULL; FfElement* rx = NULL; // reused for rf FfElement* rb = NULL; // reused for ra FfElement* t1 = NULL; FfElement* t2 = NULL; BigNumStr t1_str = {0}; BigNumStr t2_str = {0}; struct { uint32_t i; BigNumStr bsn; } p2x = {0}; FfElement* p2y = NULL; if (!ctx || !precompsig || !ctx->epid2_params) { return kEpidBadArgErr; } do { // handy shorthands: Tpm2Ctx* tpm = ctx->tpm2_ctx; EcGroup* G1 = ctx->epid2_params->G1; FiniteField* GT = ctx->epid2_params->GT; FiniteField* Fp = ctx->epid2_params->Fp; FiniteField* Fq = ctx->epid2_params->Fq; EcPoint const* h2 = ctx->h2; EcPoint const* A = ctx->A; FfElement const* x = ctx->x; PairingState* ps_ctx = ctx->epid2_params->pairing_state; const BigNumStr kOne = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}; // 1. The member expects the pre-computation is done (e12, e22, e2w, // ea2). Refer to Section 3.5 for the computation of these // values. sts = NewFfElement(Fq, &p2y); // The following variables B, K, T, R1 (elements of G1), R2 // (elements of GT), a, b, rx, rf, ra, rb, t1, t2 (256-bit // integers) are used. BREAK_ON_EPID_ERROR(sts); sts = NewEcPoint(G1, &B); BREAK_ON_EPID_ERROR(sts); sts = NewEcPoint(G1, &k); BREAK_ON_EPID_ERROR(sts); sts = NewEcPoint(G1, &t); BREAK_ON_EPID_ERROR(sts); sts = NewEcPoint(G1, &e); BREAK_ON_EPID_ERROR(sts); sts = NewFfElement(GT, &R2); BREAK_ON_EPID_ERROR(sts); sts = NewFfElement(Fp, &a); BREAK_ON_EPID_ERROR(sts); sts = NewFfElement(Fp, &rx); BREAK_ON_EPID_ERROR(sts); sts = NewFfElement(Fp, &rb); BREAK_ON_EPID_ERROR(sts); sts = NewFfElement(Fp, &t1); BREAK_ON_EPID_ERROR(sts); sts = NewFfElement(Fp, &t2); BREAK_ON_EPID_ERROR(sts); // 3. The member computes B = G1.getRandom(). // 4.a. If bsn is not provided, the member chooses randomly an integer bsn // from [1, p-1]. sts = Tpm2GetRandom(tpm, sizeof(p2x.bsn) * 8, &p2x.bsn); BREAK_ON_EPID_ERROR(sts); precompsig->rnd_bsn = p2x.bsn; // 4.b. The member computes (B, i2, y2) = G1.tpmHash(bsn). sts = EcHash(G1, (const void*)&p2x.bsn, sizeof(p2x.bsn), ctx->hash_alg, B, &p2x.i); BREAK_ON_EPID_ERROR(sts); p2x.i = htonl(p2x.i); sts = WriteEcPoint(G1, B, &precompsig->B, sizeof(precompsig->B)); BREAK_ON_EPID_ERROR(sts); sts = ReadFfElement(Fq, &precompsig->B.y, sizeof(precompsig->B.y), p2y); BREAK_ON_EPID_ERROR(sts); // 4.c. (KTPM, LTPM, ETPM, counterTPM) = TPM2_Commit(P1=h1, (s2, y2) = (i1 // || bsn, y2)), K = KTPM sts = Tpm2Commit(tpm, ctx->h1, &p2x, sizeof(p2x), p2y, k, t, e, &precompsig->rf_ctr); BREAK_ON_EPID_ERROR(sts); sts = WriteEcPoint(G1, k, &precompsig->K, sizeof(precompsig->K)); BREAK_ON_EPID_ERROR(sts); // 4.k. The member computes R1 = LTPM. sts = WriteEcPoint(G1, t, &precompsig->R1, sizeof(precompsig->R1)); BREAK_ON_EPID_ERROR(sts); // 4.d. The member chooses randomly an integer a from [1, p-1]. sts = FfGetRandom(Fp, &kOne, ctx->rnd_func, ctx->rnd_param, a); BREAK_ON_EPID_ERROR(sts); sts = WriteFfElement(Fp, a, &precompsig->a, sizeof(precompsig->a)); BREAK_ON_EPID_ERROR(sts); // 4.e. The member computes T = G1.sscmExp(h2, a). sts = EcExp(G1, h2, (BigNumStr*)&precompsig->a, t); BREAK_ON_EPID_ERROR(sts); // 4.k. The member computes T = G1.mul(T, A). sts = EcMul(G1, t, A, t); BREAK_ON_EPID_ERROR(sts); sts = WriteEcPoint(G1, t, &precompsig->T, sizeof(precompsig->T)); BREAK_ON_EPID_ERROR(sts); // 4.h. The member chooses rx, ra, rb randomly from [1, p-1]. // note : rb are reused as ra sts = FfGetRandom(Fp, &kOne, ctx->rnd_func, ctx->rnd_param, rx); BREAK_ON_EPID_ERROR(sts); sts = FfGetRandom(Fp, &kOne, ctx->rnd_func, ctx->rnd_param, rb); BREAK_ON_EPID_ERROR(sts); sts = WriteFfElement(Fp, rx, &precompsig->rx, sizeof(precompsig->rx)); BREAK_ON_EPID_ERROR(sts); sts = WriteFfElement(Fp, rb, &precompsig->rb, sizeof(precompsig->rb)); BREAK_ON_EPID_ERROR(sts); // 4.i. The member computes t1 = (- rx) mod p. sts = FfNeg(Fp, rx, t1); BREAK_ON_EPID_ERROR(sts); // 4.j. The member computes t2 = (rb - a * rx) mod p. sts = FfMul(Fp, a, rx, t2); BREAK_ON_EPID_ERROR(sts); sts = FfNeg(Fp, t2, t2); BREAK_ON_EPID_ERROR(sts); sts = FfAdd(Fp, rb, t2, t2); BREAK_ON_EPID_ERROR(sts); // 4.g. The member computes b = (a * x) mod p. sts = FfMul(Fp, a, x, a); BREAK_ON_EPID_ERROR(sts); sts = WriteFfElement(Fp, a, &precompsig->b, sizeof(precompsig->b)); BREAK_ON_EPID_ERROR(sts); // reusing rb as ra sts = FfGetRandom(Fp, &kOne, ctx->rnd_func, ctx->rnd_param, rb); BREAK_ON_EPID_ERROR(sts); sts = WriteFfElement(Fp, rb, &precompsig->ra, sizeof(precompsig->ra)); BREAK_ON_EPID_ERROR(sts); // 4.l.i e12rf = pairing(ETPM, g2) sts = Pairing(ps_ctx, e, ctx->epid2_params->g2, R2); BREAK_ON_EPID_ERROR(sts); // 4.l.ii. The member computes R2 = GT.sscmMultiExp(ea2, t1, e12rf, 1, // e22, t2, e2w, ra). sts = WriteFfElement(Fp, t1, &t1_str, sizeof(t1_str)); BREAK_ON_EPID_ERROR(sts); sts = WriteFfElement(Fp, t2, &t2_str, sizeof(t2_str)); BREAK_ON_EPID_ERROR(sts); { FfElement const* points[4]; BigNumStr const* exponents[4]; points[0] = ctx->ea2; points[1] = R2; points[2] = ctx->e22; points[3] = ctx->e2w; exponents[0] = &t1_str; exponents[1] = &kOne; exponents[2] = &t2_str; exponents[3] = (BigNumStr*)&precompsig->ra; sts = FfMultiExp(GT, points, exponents, COUNT_OF(points), R2); BREAK_ON_EPID_ERROR(sts); } sts = WriteFfElement(GT, R2, &precompsig->R2, sizeof(precompsig->R2)); BREAK_ON_EPID_ERROR(sts); sts = kEpidNoErr; } while (0); if (sts != kEpidNoErr) { (void)Tpm2ReleaseCounter(ctx->tpm2_ctx, precompsig->rf_ctr); } EpidZeroMemory(&t1_str, sizeof(t1_str)); EpidZeroMemory(&t2_str, sizeof(t2_str)); EpidZeroMemory(&p2x, sizeof(p2x)); DeleteFfElement(&p2y); DeleteEcPoint(&B); DeleteEcPoint(&k); DeleteEcPoint(&t); DeleteEcPoint(&e); DeleteFfElement(&R2); DeleteFfElement(&a); DeleteFfElement(&rx); DeleteFfElement(&rb); DeleteFfElement(&t1); DeleteFfElement(&t2); return sts; }