EpidStatus CreatePrivKey(PrivKey const* priv_key_str, EcGroup* G1, FiniteField* Fp, PrivKey_** priv_key) { EpidStatus result = kEpidErr; PrivKey_* priv_key_ = NULL; // check parameters if (!priv_key_str || !G1 || !Fp || !priv_key) return kEpidBadArgErr; do { priv_key_ = SAFE_ALLOC(sizeof(*priv_key_)); if (!priv_key_) { result = kEpidMemAllocErr; break; } result = NewEcPoint(G1, &priv_key_->A); if (kEpidNoErr != result) break; result = NewFfElement(Fp, &priv_key_->x); if (kEpidNoErr != result) break; result = NewFfElement(Fp, &priv_key_->f); if (kEpidNoErr != result) break; if (0 != memcpy_S(&priv_key_->gid, sizeof(priv_key_->gid), &priv_key_str->gid, sizeof(priv_key_str->gid))) { result = kEpidBadArgErr; break; } result = ReadEcPoint(G1, &priv_key_str->A, sizeof(priv_key_str->A), priv_key_->A); if (kEpidNoErr != result) break; result = ReadFfElement(Fp, &priv_key_str->x, sizeof(priv_key_str->x), priv_key_->x); if (kEpidNoErr != result) break; result = ReadFfElement(Fp, &priv_key_str->f, sizeof(priv_key_str->f), priv_key_->f); if (kEpidNoErr != result) break; *priv_key = priv_key_; result = kEpidNoErr; } while (0); if (kEpidNoErr != result) { DeletePrivKey(&priv_key_); } return (result); }
EpidStatus EpidSignBasic(MemberCtx const* ctx, void const* msg, size_t msg_len, void const* basename, size_t basename_len, BasicSignature* sig, BigNumStr* rnd_bsn) { EpidStatus sts = kEpidErr; EcPoint* B = NULL; EcPoint* t = NULL; // temp value in G1 EcPoint* k = NULL; EcPoint* e = NULL; FfElement* R2 = NULL; FfElement* p2y = NULL; FfElement* t1 = NULL; FfElement* t2 = NULL; FfElement* a = NULL; FfElement* b = NULL; FfElement* rx = NULL; FfElement* ra = NULL; FfElement* rb = NULL; struct p2x_t { uint32_t i; uint8_t bsn[1]; }* p2x = NULL; FfElement* t3 = NULL; // temporary for multiplication FfElement* c = NULL; uint8_t* digest = NULL; PreComputedSignature curr_presig = {0}; if (!ctx || !sig) { return kEpidBadArgErr; } if (!msg && (0 != msg_len)) { // if message is non-empty it must have both length and content return kEpidBadArgErr; } if (!basename && (0 != basename_len)) { // if basename is non-empty it must have both length and content return kEpidBadArgErr; } if (!ctx->epid2_params) { return kEpidBadArgErr; } do { FiniteField* Fp = ctx->epid2_params->Fp; SignCommitOutput commit_out = {0}; FpElemStr c_str = {0}; EcGroup* G1 = ctx->epid2_params->G1; FiniteField* GT = ctx->epid2_params->GT; FiniteField* Fq = ctx->epid2_params->Fq; 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}; BigNumStr t1_str = {0}; BigNumStr t2_str = {0}; size_t digest_size = 0; uint16_t* rf_ctr = (uint16_t*)&ctx->rf_ctr; FfElement const* x = ctx->x; if (basename) { if (!IsBasenameAllowed(ctx->allowed_basenames, basename, basename_len)) { sts = kEpidBadArgErr; 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(Fq, &p2y); BREAK_ON_EPID_ERROR(sts); sts = NewFfElement(Fp, &t1); BREAK_ON_EPID_ERROR(sts); sts = NewFfElement(Fp, &t2); BREAK_ON_EPID_ERROR(sts); p2x = (struct p2x_t*)SAFE_ALLOC(sizeof(struct p2x_t) + basename_len - 1); if (!p2x) { sts = kEpidMemAllocErr; break; } sts = NewFfElement(Fp, &a); BREAK_ON_EPID_ERROR(sts); sts = NewFfElement(Fp, &b); BREAK_ON_EPID_ERROR(sts); sts = NewFfElement(Fp, &rx); BREAK_ON_EPID_ERROR(sts); sts = NewFfElement(Fp, &ra); BREAK_ON_EPID_ERROR(sts); sts = NewFfElement(Fp, &rb); BREAK_ON_EPID_ERROR(sts); sts = MemberGetPreSig((MemberCtx*)ctx, &curr_presig); BREAK_ON_EPID_ERROR(sts); // 3. If the pre-computed signature pre-sigma exists, the member // loads (B, K, T, a, b, rx, rf, ra, rb, R1, R2) from // pre-sigma. Refer to Section 4.4 for the computation of // these values. sts = ReadFfElement(Fp, &curr_presig.a, sizeof(curr_presig.a), a); BREAK_ON_EPID_ERROR(sts); sts = ReadFfElement(Fp, &curr_presig.b, sizeof(curr_presig.b), b); BREAK_ON_EPID_ERROR(sts); sts = ReadFfElement(Fp, &curr_presig.rx, sizeof(curr_presig.rx), rx); BREAK_ON_EPID_ERROR(sts); sts = ReadFfElement(Fp, &curr_presig.ra, sizeof(curr_presig.ra), ra); BREAK_ON_EPID_ERROR(sts); sts = ReadFfElement(Fp, &curr_presig.rb, sizeof(curr_presig.rb), rb); BREAK_ON_EPID_ERROR(sts); // If the basename is provided, use it, otherwise use presig B if (basename) { // 3.a. The member computes (B, i2, y2) = G1.tpmHash(bsn). sts = EcHash(G1, basename, basename_len, ctx->hash_alg, B, &p2x->i); BREAK_ON_EPID_ERROR(sts); p2x->i = htonl(p2x->i); sts = WriteEcPoint(G1, B, &commit_out.B, sizeof(commit_out.B)); BREAK_ON_EPID_ERROR(sts); sts = ReadFfElement(Fq, &commit_out.B.y, sizeof(commit_out.B.y), p2y); BREAK_ON_EPID_ERROR(sts); // b.i. (KTPM, LTPM, ETPM, counterTPM) = TPM2_Commit(P1=h1,(s2, y2) = (i2 // || bsn, y2)). // b.ii.K = KTPM. if (0 != memcpy_S((void*)p2x->bsn, basename_len, basename, basename_len)) { sts = kEpidBadArgErr; break; } sts = Tpm2Commit(ctx->tpm2_ctx, ctx->h1, p2x, sizeof(p2x->i) + basename_len, p2y, k, t, e, (uint16_t*)&ctx->rf_ctr); BREAK_ON_EPID_ERROR(sts); sts = WriteEcPoint(G1, k, &commit_out.K, sizeof(commit_out.K)); BREAK_ON_EPID_ERROR(sts); // c.i. The member computes R1 = LTPM. sts = WriteEcPoint(G1, t, &commit_out.R1, sizeof(commit_out.R1)); BREAK_ON_EPID_ERROR(sts); // c.ii. e12rf = pairing(ETPM, g2) sts = Pairing(ps_ctx, e, ctx->epid2_params->g2, R2); BREAK_ON_EPID_ERROR(sts); // c.iii. R2 = GT.sscmMultiExp(ea2, t1, e12rf, 1, e22, t2, e2w,ra). // 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); 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*)&curr_presig.ra; sts = FfMultiExp(GT, points, exponents, COUNT_OF(points), R2); BREAK_ON_EPID_ERROR(sts); } sts = WriteFfElement(GT, R2, &commit_out.R2, sizeof(commit_out.R2)); BREAK_ON_EPID_ERROR(sts); // d. The member over-writes the counterTPM, B, K, R1 and R2 values. } else { if (!rnd_bsn) { sts = kEpidBadArgErr; break; } sts = ReadEcPoint(G1, &curr_presig.B, sizeof(curr_presig.B), B); BREAK_ON_EPID_ERROR(sts); commit_out.B = curr_presig.B; commit_out.K = curr_presig.K; commit_out.R1 = curr_presig.R1; ((MemberCtx*)ctx)->rf_ctr = curr_presig.rf_ctr; commit_out.R2 = curr_presig.R2; *rnd_bsn = curr_presig.rnd_bsn; } commit_out.T = curr_presig.T; sts = HashSignCommitment(Fp, ctx->hash_alg, &ctx->pub_key, &commit_out, msg, msg_len, &c_str); BREAK_ON_EPID_ERROR(sts); digest_size = EpidGetHashSize(ctx->hash_alg); digest = (uint8_t*)SAFE_ALLOC(digest_size); if (!digest) { sts = kEpidNoMemErr; break; } memcpy_S(digest + digest_size - sizeof(c_str), sizeof(c_str), &c_str, sizeof(c_str)); sts = NewFfElement(Fp, &t3); BREAK_ON_EPID_ERROR(sts); sts = NewFfElement(Fp, &c); BREAK_ON_EPID_ERROR(sts); sts = ReadFfElement(Fp, &c_str, sizeof(c_str), c); BREAK_ON_EPID_ERROR(sts); // 7. The member computes sx = (rx + c * x) mod p. sts = FfMul(Fp, c, x, t3); BREAK_ON_EPID_ERROR(sts); sts = FfAdd(Fp, rx, t3, t3); BREAK_ON_EPID_ERROR(sts); sts = WriteFfElement(Fp, t3, &sig->sx, sizeof(sig->sx)); BREAK_ON_EPID_ERROR(sts); // 8. The member computes sf = (rf + c * f) mod p. sts = Tpm2Sign(ctx->tpm2_ctx, digest, digest_size, *rf_ctr, NULL, t3); BREAK_ON_EPID_ERROR(sts); sts = WriteFfElement(Fp, t3, &sig->sf, sizeof(sig->sf)); BREAK_ON_EPID_ERROR(sts); // 9. The member computes sa = (ra + c * a) mod p. sts = FfMul(Fp, c, a, t3); BREAK_ON_EPID_ERROR(sts); sts = FfAdd(Fp, ra, t3, t3); BREAK_ON_EPID_ERROR(sts); sts = WriteFfElement(Fp, t3, &sig->sa, sizeof(sig->sa)); BREAK_ON_EPID_ERROR(sts); // 10. The member computes sb = (rb + c * b) mod p. sts = FfMul(Fp, c, b, t3); BREAK_ON_EPID_ERROR(sts); sts = FfAdd(Fp, rb, t3, t3); BREAK_ON_EPID_ERROR(sts); sts = WriteFfElement(Fp, t3, &sig->sb, sizeof(sig->sb)); BREAK_ON_EPID_ERROR(sts); sig->B = commit_out.B; sig->K = commit_out.K; sig->T = commit_out.T; sig->c = c_str; sts = kEpidNoErr; } while (0); if (sts != kEpidNoErr) { (void)Tpm2ReleaseCounter(ctx->tpm2_ctx, (uint16_t)ctx->rf_ctr); (void)Tpm2ReleaseCounter(ctx->tpm2_ctx, curr_presig.rf_ctr); } else if (basename) { (void)Tpm2ReleaseCounter(ctx->tpm2_ctx, curr_presig.rf_ctr); } EpidZeroMemory(&curr_presig, sizeof(curr_presig)); DeleteEcPoint(&B); DeleteEcPoint(&k); DeleteEcPoint(&t); DeleteEcPoint(&e); DeleteFfElement(&R2); DeleteFfElement(&p2y); DeleteFfElement(&t1); DeleteFfElement(&t2); DeleteFfElement(&a); DeleteFfElement(&b); DeleteFfElement(&rx); DeleteFfElement(&ra); DeleteFfElement(&rb); SAFE_FREE(p2x); DeleteFfElement(&t3); DeleteFfElement(&c); SAFE_FREE(digest); return sts; }
/// Parse a file with a revocation list of any type static EpidStatus EpidParseRlFile(void const* buf, size_t len, EpidCaCertificate const* cert, void* rl, size_t* rl_len, EpidFileType file_type) { size_t min_rl_file_size = 0; size_t empty_rl_size = 0; size_t rl_entry_size = 0; EpidStatus result = kEpidErr; EpidFileHeader const* file_header = (EpidFileHeader*)buf; void const* buf_rl = (void const*)((unsigned char*)buf + sizeof(EpidFileHeader)); size_t buf_rl_len = 0; EcdsaSignature const* signature = NULL; if (!buf || !cert || !rl_len) return kEpidBadArgErr; switch (file_type) { case kPrivRlFile: empty_rl_size = sizeof(PrivRl) - sizeof(((PrivRl*)0)->f[0]); rl_entry_size = sizeof(((PrivRl*)0)->f[0]); min_rl_file_size = sizeof(EpidFileHeader) + sizeof(PrivRl) - sizeof(((PrivRl*)0)->f[0]) + sizeof(EcdsaSignature); break; case kSigRlFile: empty_rl_size = sizeof(SigRl) - sizeof(((SigRl*)0)->bk[0]); rl_entry_size = sizeof(((SigRl*)0)->bk[0]); min_rl_file_size = sizeof(EpidFileHeader) + sizeof(SigRl) - sizeof(((SigRl*)0)->bk[0]) + sizeof(EcdsaSignature); break; case kGroupRlFile: empty_rl_size = sizeof(GroupRl) - sizeof(((GroupRl*)0)->gid[0]); rl_entry_size = sizeof(((GroupRl*)0)->gid[0]); min_rl_file_size = sizeof(EpidFileHeader) + sizeof(GroupRl) - sizeof(((GroupRl*)0)->gid[0]) + sizeof(EcdsaSignature); break; default: return kEpidErr; } if (min_rl_file_size > len) return kEpidBadArgErr; // Verify that Intel(R) EPID file header in the buffer is correct if (0 != memcmp(&file_header->epid_version, &kEpidVersion, sizeof(kEpidVersion))) { return kEpidBadArgErr; } if (0 != memcmp(&file_header->file_type, &kEpidFileTypeCode[file_type], sizeof(file_header->file_type))) { return kEpidBadArgErr; } // Verify that CA certificate is correct result = EpidVerifyCaCertificate(cert); if (kEpidNoErr != result) return result; // Verify that RL in file buffer contains of integer number of entries buf_rl_len = len - sizeof(EpidFileHeader) - sizeof(EcdsaSignature); if (0 != ((buf_rl_len - empty_rl_size) % rl_entry_size)) { return kEpidBadArgErr; } signature = (EcdsaSignature*)((unsigned char*)buf + len - sizeof(EcdsaSignature)); // Authenticate signature for buffer result = EcdsaVerifyBuffer(buf, len - sizeof(EcdsaSignature), (EcdsaPublicKey*)&cert->pubkey, signature); if (kEpidSigValid != result) return result; buf_rl_len = len - sizeof(EpidFileHeader) - sizeof(EcdsaSignature); // If pointer to output buffer is NULL it should return required size of RL if (!rl) { *rl_len = buf_rl_len; return kEpidNoErr; } if (*rl_len < buf_rl_len) return kEpidBadArgErr; *rl_len = buf_rl_len; // Copy revocation list from file buffer to output // Memory copy is used to copy a revocation list of variable length if (0 != memcpy_S(rl, *rl_len, buf_rl, buf_rl_len)) return kEpidBadArgErr; return kEpidNoErr; }
EpidStatus EpidSign(MemberCtx const* ctx, void const* msg, size_t msg_len, void const* basename, size_t basename_len, SigRl const* sig_rl, size_t sig_rl_size, EpidSignature* sig, size_t sig_len) { EpidStatus result = kEpidErr; uint32_t num_sig_rl = 0; OctStr32 octstr32_0 = {{0x00, 0x00, 0x00, 0x00}}; if (!ctx || !sig) { return kEpidBadArgErr; } if (!ctx->pub_key) { return kEpidBadArgErr; } if (!msg && (0 != msg_len)) { // if message is non-empty it must have both length and content return kEpidBadArgErr; } if (!basename && (0 != basename_len)) { // if basename is non-empty it must have both length and content return kEpidBadArgErr; } if (sig_rl && (sig_rl_size < sizeof(SigRl) - sizeof(SigRlEntry))) { return kEpidBadArgErr; } if (sig_rl && EpidGetSigSize(sig_rl) > sig_len) { return kEpidBadArgErr; } // 11. The member sets sigma0 = (B, K, T, c, sx, sf, sa, sb). result = EpidSignBasic(ctx, msg, msg_len, basename, basename_len, &sig->sigma0); if (kEpidNoErr != result) { return result; } if (!sig_rl) { // 12. If SigRL is not provided as input, // a. The member sets RLver = 0 and n2 = 0. // b. The member outputs (sigma0, RLver, n2) and returns "succeeded". sig->rl_ver = octstr32_0; sig->n2 = octstr32_0; return kEpidNoErr; } else { uint32_t i = 0; EpidStatus nr_prove_status = kEpidNoErr; // 13. If SigRL is provided as input, the member proceeds with // the following steps: // a. The member verifies that gid in public key and in SigRL // match. if (!IsSigRlValid(&ctx->pub_key->gid, sig_rl, sig_rl_size)) { return kEpidBadArgErr; } // b. The member copies RLver and n2 values in SigRL to the // signature. if (0 != memcpy_S(&sig->rl_ver, sizeof(sig->rl_ver), &sig_rl->version, sizeof(sig_rl->version))) return kEpidBadArgErr; if (0 != memcpy_S(&sig->n2, sizeof(sig->n2), &sig_rl->n2, sizeof(sig_rl->n2))) return kEpidBadArgErr; // c. For i = 0, ..., n2-1, the member computes sigma[i] = // nrProve(f, B, K, B[i], K[i]). The details of nrProve() // will be given in the next subsection. num_sig_rl = ntohl(sig_rl->n2); for (i = 0; i < num_sig_rl; i++) { result = EpidNrProve(ctx, msg, msg_len, &sig->sigma0, &sig_rl->bk[i], &sig->sigma[i]); if (kEpidNoErr != result) { nr_prove_status = result; } } if (kEpidNoErr != nr_prove_status) { memset(&sig->sigma[0], 0, num_sig_rl * sizeof(sig->sigma[0])); return nr_prove_status; } } // d. The member outputs (sigma0, RLver, n2, sigma[0], ..., // sigma[n2-1]). // e. If any of the nrProve() functions outputs "failed", the // member returns "revoked", otherwise returns "succeeded". return kEpidNoErr; }