/*############################################################################ # Copyright 2016-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. ############################################################################*/ /*! * \file * \brief Intel Intel(R) EPID 1.1 Verifier context implementation. */ #include "epid/verifier/1.1/src/context.h" #include "epid/common/src/endian_convert.h" #include "epid/common/src/memory.h" #include "epid/verifier/1.1/api.h" /// Handle SDK Error with Break #define BREAK_ON_EPID_ERROR(ret) \ \ if (kEpidNoErr != (ret)) { \ break; \ } /// create Verifier precomp of the Epid11VerifierCtx static EpidStatus DoPrecomputation(Epid11VerifierCtx* ctx); /// Read Verifier precomp static EpidStatus ReadPrecomputation(Epid11VerifierPrecomp const* precomp_str, Epid11VerifierCtx* ctx); /// Internal function to prove if group based revocation list is valid static bool Epid11IsGroupRlValid(Epid11GroupRl const* group_rl, size_t grp_rl_size) { const size_t kMinGroupRlSize = sizeof(Epid11GroupRl) - sizeof(Epid11GroupId); size_t input_grp_rl_size = 0; if (!group_rl) { return false; } if (grp_rl_size < kMinGroupRlSize) { return false; } if (ntohl(group_rl->n3) > (SIZE_MAX - kMinGroupRlSize) / sizeof(Epid11GroupId)) { return false; } input_grp_rl_size = kMinGroupRlSize + (ntohl(group_rl->n3) * sizeof(Epid11GroupId)); if (input_grp_rl_size != grp_rl_size) { return false; } return true; } /// Internal function to prove if signature based revocation list is valid bool Epid11IsSigRlValid(Epid11GroupId const* gid, Epid11SigRl const* sig_rl, size_t sig_rl_size) { const size_t kMinSigRlSize = sizeof(Epid11SigRl) - sizeof(Epid11SigRlEntry); size_t input_sig_rl_size = 0; if (!gid || !sig_rl || kMinSigRlSize > sig_rl_size) { return false; } if (ntohl(sig_rl->n2) > (SIZE_MAX - kMinSigRlSize) / sizeof(sig_rl->bk[0])) { return false; } // sanity check of intput SigRl size input_sig_rl_size = kMinSigRlSize + ntohl(sig_rl->n2) * sizeof(sig_rl->bk[0]); if (input_sig_rl_size != sig_rl_size) { return false; } // verify that gid given and gid in SigRl match if (0 != memcmp(gid, &sig_rl->gid, sizeof(*gid))) { return false; } return true; } /// Internal function to verify if Intel(R) EPID 1.1 private key based /// revocation list is valid static bool IsEpid11PrivRlValid(Epid11GroupId const* gid, Epid11PrivRl const* priv_rl, size_t priv_rl_size) { const size_t kMinPrivRlSize = sizeof(Epid11PrivRl) - sizeof(FpElemStr); size_t input_priv_rl_size = 0; if (!gid || !priv_rl || kMinPrivRlSize > priv_rl_size) { return false; } if (ntohl(priv_rl->n1) > (SIZE_MAX - kMinPrivRlSize) / sizeof(priv_rl->f[0])) { return false; } // sanity check of input Epid11PrivRl size input_priv_rl_size = kMinPrivRlSize + ntohl(priv_rl->n1) * sizeof(priv_rl->f[0]); if (input_priv_rl_size != priv_rl_size) { return false; } // verify that gid given and gid in Epid11PrivRl match if (0 != memcmp(gid, &priv_rl->gid, sizeof(*gid))) { return false; } return true; } EpidStatus Epid11VerifierCreate(Epid11GroupPubKey const* pub_key, Epid11VerifierPrecomp const* precomp, Epid11VerifierCtx** ctx) { EpidStatus result = kEpidErr; Epid11VerifierCtx* verifier_ctx = NULL; if (!pub_key || !ctx) { return kEpidBadArgErr; } do { // Allocate memory for VerifierCtx verifier_ctx = SAFE_ALLOC(sizeof(Epid11VerifierCtx)); if (!verifier_ctx) { result = kEpidMemAllocErr; break; } // Internal representation of Epid11Params result = CreateEpid11Params(&verifier_ctx->epid11_params); BREAK_ON_EPID_ERROR(result); // Internal representation of Group Pub Key result = CreateEpid11GroupPubKey(pub_key, verifier_ctx->epid11_params->G1, verifier_ctx->epid11_params->G2, &verifier_ctx->pub_key); BREAK_ON_EPID_ERROR(result); // Store group public key strings for later use result = SetKeySpecificEpid11CommitValues(pub_key, &verifier_ctx->commit_values); if (kEpidNoErr != result) { break; } // Allocate verifier_ctx->e12 result = NewFfElement(verifier_ctx->epid11_params->GT, &verifier_ctx->e12); BREAK_ON_EPID_ERROR(result); // Allocate verifier_ctx->e22 result = NewFfElement(verifier_ctx->epid11_params->GT, &verifier_ctx->e22); BREAK_ON_EPID_ERROR(result); // Allocate verifier_ctx->e2w result = NewFfElement(verifier_ctx->epid11_params->GT, &verifier_ctx->e2w); BREAK_ON_EPID_ERROR(result); // precomputation if (precomp != NULL) { result = ReadPrecomputation(precomp, verifier_ctx); } else { result = DoPrecomputation(verifier_ctx); } BREAK_ON_EPID_ERROR(result); verifier_ctx->sig_rl = NULL; verifier_ctx->group_rl = NULL; verifier_ctx->priv_rl = NULL; *ctx = verifier_ctx; result = kEpidNoErr; } while (0); if (kEpidNoErr != result && verifier_ctx) { DeleteFfElement(&verifier_ctx->e2w); DeleteFfElement(&verifier_ctx->e22); DeleteFfElement(&verifier_ctx->e12); DeleteEpid11GroupPubKey(&verifier_ctx->pub_key); DeleteEpid11Params(&verifier_ctx->epid11_params); SAFE_FREE(verifier_ctx); } return result; } void Epid11VerifierDelete(Epid11VerifierCtx** ctx) { if (ctx && *ctx) { DeleteFfElement(&(*ctx)->e2w); DeleteFfElement(&(*ctx)->e22); DeleteFfElement(&(*ctx)->e12); DeleteEpid11GroupPubKey(&(*ctx)->pub_key); DeleteEpid11Params(&(*ctx)->epid11_params); (*ctx)->priv_rl = NULL; (*ctx)->sig_rl = NULL; (*ctx)->group_rl = NULL; DeleteEcPoint(&(*ctx)->basename_hash); SAFE_FREE((*ctx)->basename); (*ctx)->basename_len = 0; SAFE_FREE(*ctx); } } EpidStatus Epid11VerifierWritePrecomp(Epid11VerifierCtx const* ctx, Epid11VerifierPrecomp* precomp) { EpidStatus result = kEpidErr; FfElement* e12 = NULL; // an element in GT FfElement* e22 = NULL; // an element in GT FfElement* e2w = NULL; // an element in GT FiniteField* GT = NULL; // Finite field GT(Fq6) if (!ctx || !ctx->e12 || !ctx->e22 || !ctx->e2w || !ctx->epid11_params || !(ctx->epid11_params->GT) || !ctx->pub_key || !precomp) { return kEpidBadArgErr; } e12 = ctx->e12; e22 = ctx->e22; e2w = ctx->e2w; GT = ctx->epid11_params->GT; precomp->gid = ctx->pub_key->gid; result = WriteFfElement(GT, e12, &(precomp->e12), sizeof(precomp->e12)); if (kEpidNoErr != result) { return result; } result = WriteFfElement(GT, e22, &(precomp->e22), sizeof(precomp->e22)); if (kEpidNoErr != result) { return result; } result = WriteFfElement(GT, e2w, &(precomp->e2w), sizeof(precomp->e2w)); if (kEpidNoErr != result) { return result; } return result; } EpidStatus Epid11VerifierSetPrivRl(Epid11VerifierCtx* ctx, Epid11PrivRl const* priv_rl, size_t priv_rl_size) { if (!ctx || !priv_rl || !ctx->pub_key) { return kEpidBadArgErr; } if (!IsEpid11PrivRlValid(&ctx->pub_key->gid, priv_rl, priv_rl_size)) { return kEpidBadArgErr; } // Do not set an older version of Epid11PrivRl if (ctx->priv_rl) { unsigned int current_ver = 0; unsigned int incoming_ver = 0; current_ver = ntohl(ctx->priv_rl->version); incoming_ver = ntohl(priv_rl->version); if (current_ver >= incoming_ver) { return kEpidBadArgErr; } } ctx->priv_rl = priv_rl; return kEpidNoErr; } EpidStatus Epid11VerifierSetSigRl(Epid11VerifierCtx* ctx, Epid11SigRl const* sig_rl, size_t sig_rl_size) { if (!ctx || !sig_rl || !ctx->pub_key) { return kEpidBadArgErr; } // Do not set an older version of sig rl if (ctx->sig_rl) { unsigned int current_ver = 0; unsigned int incoming_ver = 0; current_ver = ntohl(ctx->sig_rl->version); incoming_ver = ntohl(sig_rl->version); if (current_ver >= incoming_ver) { return kEpidBadArgErr; } } if (!Epid11IsSigRlValid(&ctx->pub_key->gid, sig_rl, sig_rl_size)) { return kEpidBadArgErr; } ctx->sig_rl = sig_rl; return kEpidNoErr; } EpidStatus Epid11VerifierSetGroupRl(Epid11VerifierCtx* ctx, Epid11GroupRl const* grp_rl, size_t grp_rl_size) { if (!ctx || !grp_rl || !ctx->pub_key) { return kEpidBadArgErr; } if (!Epid11IsGroupRlValid(grp_rl, grp_rl_size)) { return kEpidBadArgErr; } // Do not set an older version of group rl if (ctx->group_rl) { unsigned int current_ver = 0; unsigned int incoming_ver = 0; current_ver = ntohl(ctx->group_rl->version); incoming_ver = ntohl(grp_rl->version); if (current_ver >= incoming_ver) { return kEpidBadArgErr; } } ctx->group_rl = grp_rl; return kEpidNoErr; } EpidStatus Epid11VerifierSetBasename(Epid11VerifierCtx* ctx, void const* basename, size_t basename_len) { EpidStatus result = kEpidErr; EcPoint* basename_hash = NULL; uint8_t* basename_buffer = NULL; if (!ctx || !ctx->epid11_params || !ctx->epid11_params->G3) { return kEpidBadArgErr; } if (!basename && basename_len > 0) { return kEpidBadArgErr; } if (!basename) { ctx->basename_len = 0; DeleteEcPoint(&ctx->basename_hash); SAFE_FREE(ctx->basename); return kEpidNoErr; } do { EcGroup* G3 = ctx->epid11_params->G3; result = NewEcPoint(G3, &basename_hash); if (kEpidNoErr != result) { break; } result = Epid11EcHash(G3, basename, basename_len, basename_hash); if (kEpidNoErr != result) { break; } if (basename_len > 0) { basename_buffer = SAFE_ALLOC(basename_len); if (!basename_buffer) { result = kEpidMemAllocErr; break; } } ctx->basename_len = basename_len; if (basename_len > 0) { // memcpy is used to copy variable length basename if (0 != memcpy_S(basename_buffer, ctx->basename_len, basename, basename_len)) { result = kEpidErr; break; } } DeleteEcPoint(&ctx->basename_hash); SAFE_FREE(ctx->basename); ctx->basename = basename_buffer; ctx->basename_hash = basename_hash; result = kEpidNoErr; } while (0); if (kEpidNoErr != result) { DeleteEcPoint(&basename_hash); SAFE_FREE(basename_buffer); } return result; } static EpidStatus DoPrecomputation(Epid11VerifierCtx* ctx) { EpidStatus result = kEpidErr; FfElement* e12 = NULL; FfElement* e22 = NULL; FfElement* e2w = NULL; Epid11Params_* params = NULL; Epid11GroupPubKey_* pub_key = NULL; Epid11PairingState* ps_ctx = NULL; if (!ctx) { return kEpidBadArgErr; } if (!ctx->epid11_params || !ctx->epid11_params->GT || !ctx->epid11_params->pairing_state || !ctx->pub_key || !ctx->e12 || !ctx->e22 || !ctx->e2w) { return kEpidBadArgErr; } pub_key = ctx->pub_key; params = ctx->epid11_params; e12 = ctx->e12; e22 = ctx->e22; e2w = ctx->e2w; ps_ctx = params->pairing_state; // do precomputation // 1. The verifier computes e12 = pairing(h1, g2). result = Epid11Pairing(ps_ctx, pub_key->h1, params->g2, e12); if (kEpidNoErr != result) { return result; } // 2. The verifier computes e22 = pairing(h2, g2). result = Epid11Pairing(ps_ctx, pub_key->h2, params->g2, e22); if (kEpidNoErr != result) { return result; } // 3. The verifier computes e2w = pairing(h2, w). result = Epid11Pairing(ps_ctx, pub_key->h2, pub_key->w, e2w); if (kEpidNoErr != result) { return result; } return kEpidNoErr; } static EpidStatus ReadPrecomputation(Epid11VerifierPrecomp const* precomp_str, Epid11VerifierCtx* ctx) { EpidStatus result = kEpidErr; FfElement* e12 = NULL; FfElement* e22 = NULL; FfElement* e2w = NULL; FiniteField* GT = NULL; Epid11Params_* params = NULL; unsigned int current_gid = 0; unsigned int incoming_gid = 0; if (!ctx) { return kEpidBadArgErr; } if (!ctx->epid11_params || !ctx->epid11_params->GT || !ctx->e12 || !ctx->e22 || !ctx->e2w) { return kEpidBadArgErr; } if (!ctx->pub_key || !precomp_str) return kEpidBadArgErr; current_gid = ntohl(ctx->pub_key->gid); incoming_gid = ntohl(precomp_str->gid); if (current_gid != incoming_gid) { return kEpidBadArgErr; } params = ctx->epid11_params; GT = params->GT; e12 = ctx->e12; e22 = ctx->e22; e2w = ctx->e2w; result = ReadFfElement(GT, &precomp_str->e12, sizeof(precomp_str->e12), e12); if (kEpidNoErr != result) { return result; } result = ReadFfElement(GT, &precomp_str->e22, sizeof(precomp_str->e22), e22); if (kEpidNoErr != result) { return result; } result = ReadFfElement(GT, &precomp_str->e2w, sizeof(precomp_str->e2w), e2w); if (kEpidNoErr != result) { return result; } return kEpidNoErr; }