| /*############################################################################ |
| # 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 Epid11NrVerify implementation. |
| */ |
| #include "epid/common/math/hash.h" |
| #include "epid/common/src/endian_convert.h" |
| #include "epid/common/src/memory.h" |
| #include "epid/verifier/1.1/api.h" |
| #include "epid/verifier/1.1/src/context.h" |
| #include "ext/ipp/include/ippcp.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])) |
| #pragma pack(1) |
| /// Storage for values to create commitment in NrVerify algorithm |
| typedef struct Epid11NrVerifyCommitValues { |
| BigNumStr p_tick; //!< A large prime (256-bit) |
| Epid11G3ElemStr g3; //!< Generator of G3 (512-bit) |
| Epid11G3ElemStr B; //!< (element of G3): part of basic signature Sigma0 |
| Epid11G3ElemStr K; //!< (element of G3): part of basic signature Sigma0 |
| Epid11G3ElemStr B_tick; //!< (element of G3): one entry in SigRL |
| Epid11G3ElemStr K_tick; //!< (element of G3): one entry in SigRL |
| Epid11G3ElemStr T; //!< element of G3 |
| Epid11G3ElemStr R1; //!< element of G3 |
| Epid11G3ElemStr R2; //!< element of G3 |
| uint32_t msg_len; //!< length of the message |
| uint8_t msg[1]; //!< message |
| } Epid11NrVerifyCommitValues; |
| #pragma pack() |
| |
| EpidStatus Epid11NrVerify(Epid11VerifierCtx const* ctx, |
| Epid11BasicSignature const* sig, void const* msg, |
| size_t msg_len, Epid11SigRlEntry const* sigrl_entry, |
| Epid11NrProof const* proof) { |
| size_t const cv_header_len = |
| sizeof(Epid11NrVerifyCommitValues) - sizeof(uint8_t); |
| Epid11NrVerifyCommitValues* commit_values = NULL; |
| size_t const commit_len = sizeof(Epid11NrVerifyCommitValues) + msg_len - 1; |
| EpidStatus res = kEpidErr; |
| // Epid11 G3 elements |
| EcPoint* T = NULL; |
| EcPoint* R1 = NULL; |
| EcPoint* R2 = NULL; |
| |
| EcPoint* K = NULL; |
| EcPoint* B = NULL; |
| EcPoint* K_tick = NULL; |
| EcPoint* B_tick = NULL; |
| |
| // Big integers |
| BigNum* smu = NULL; |
| BigNum* snu = NULL; |
| BigNum* nc_tick_bn = NULL; |
| Sha256Digest commit_hash; |
| |
| if (!ctx || !sig || !proof || !sigrl_entry) { |
| return kEpidBadArgErr; |
| } |
| if (!msg && (0 != msg_len)) { |
| return kEpidBadArgErr; |
| } |
| if (msg_len > (UINT_MAX - cv_header_len)) { |
| return kEpidBadArgErr; |
| } |
| if (!ctx->epid11_params) { |
| return kEpidBadArgErr; |
| } |
| do { |
| bool cmp_result = false; |
| // handy shorthands: |
| EcGroup* G3 = ctx->epid11_params->G3; |
| BigNum* p_tick_bn = ctx->epid11_params->p_tick; |
| |
| if (!G3 || !p_tick_bn) { |
| res = kEpidBadArgErr; |
| BREAK_ON_EPID_ERROR(res); |
| } |
| |
| commit_values = SAFE_ALLOC(commit_len); |
| if (commit_values == NULL) { |
| res = kEpidMemAllocErr; |
| break; |
| } |
| // 1. We use the following variables T, R1, R2 (elements of G3), and c, smu, |
| // snu, nc (big integers). |
| res = NewEcPoint(G3, &T); |
| BREAK_ON_EPID_ERROR(res); |
| res = NewEcPoint(G3, &R1); |
| BREAK_ON_EPID_ERROR(res); |
| res = NewEcPoint(G3, &R2); |
| BREAK_ON_EPID_ERROR(res); |
| |
| res = NewEcPoint(G3, &K); |
| BREAK_ON_EPID_ERROR(res); |
| res = NewEcPoint(G3, &B); |
| BREAK_ON_EPID_ERROR(res); |
| res = NewEcPoint(G3, &K_tick); |
| BREAK_ON_EPID_ERROR(res); |
| res = NewEcPoint(G3, &B_tick); |
| BREAK_ON_EPID_ERROR(res); |
| |
| res = NewBigNum(sizeof(proof->smu), &smu); |
| BREAK_ON_EPID_ERROR(res); |
| res = NewBigNum(sizeof(proof->smu), &snu); |
| BREAK_ON_EPID_ERROR(res); |
| |
| res = NewBigNum(sizeof(FpElemStr), &nc_tick_bn); |
| BREAK_ON_EPID_ERROR(res); |
| |
| // 2. The verifier verifies that G3.inGroup(T) = true. |
| res = ReadEcPoint(G3, &(proof->T), sizeof(proof->T), T); |
| if (kEpidNoErr != res) { |
| res = kEpidBadArgErr; |
| break; |
| } |
| |
| // 3. The verifier verifies that G3.isIdentity(T) = false. |
| res = EcIsIdentity(G3, T, &(cmp_result)); |
| BREAK_ON_EPID_ERROR(res); |
| if (cmp_result) { |
| res = kEpidBadArgErr; |
| break; |
| } |
| |
| // 4. The verifier verifies that smu, snu in [0, p'-1]. |
| res = WriteBigNum(ctx->epid11_params->p_tick, sizeof(commit_values->p_tick), |
| &commit_values->p_tick); |
| BREAK_ON_EPID_ERROR(res); |
| if (memcmp(&proof->smu, &commit_values->p_tick, sizeof(FpElemStr)) >= 0 || |
| memcmp(&proof->snu, &commit_values->p_tick, sizeof(FpElemStr)) >= 0) { |
| res = kEpidBadArgErr; |
| break; |
| } |
| // 5. The verifier computes nc = (- c) mod p'. |
| res = ReadBigNum(&(proof->c), sizeof(proof->c), nc_tick_bn); |
| BREAK_ON_EPID_ERROR(res); |
| res = BigNumMod(nc_tick_bn, p_tick_bn, nc_tick_bn); |
| BREAK_ON_EPID_ERROR(res); |
| // (-c) mod p' == p' - (c mod p') |
| res = BigNumSub(p_tick_bn, nc_tick_bn, nc_tick_bn); |
| BREAK_ON_EPID_ERROR(res); |
| |
| // 6. The verifier computes R1 = G3.multiExp(K, smu, B, snu). |
| res = ReadEcPoint(G3, &(sig->K), sizeof(sig->K), K); |
| if (kEpidNoErr != res) { |
| res = kEpidBadArgErr; |
| break; |
| } |
| res = ReadEcPoint(G3, &(sig->B), sizeof(sig->B), B); |
| if (kEpidNoErr != res) { |
| res = kEpidBadArgErr; |
| break; |
| } |
| res = ReadBigNum(&(proof->smu), sizeof(proof->smu), smu); |
| BREAK_ON_EPID_ERROR(res); |
| res = ReadBigNum(&(proof->snu), sizeof(proof->snu), snu); |
| BREAK_ON_EPID_ERROR(res); |
| { |
| EcPoint const* points[2]; |
| BigNum const* exponents[2]; |
| points[0] = K; |
| points[1] = B; |
| exponents[0] = smu; |
| exponents[1] = snu; |
| res = EcMultiExpBn(G3, points, exponents, COUNT_OF(points), R1); |
| BREAK_ON_EPID_ERROR(res); |
| } |
| // 7. The verifier computes R2 = G3.multiExp(K', smu, B', snu, T, nc). |
| res = ReadEcPoint(G3, &(sigrl_entry->k), sizeof(sigrl_entry->k), K_tick); |
| if (kEpidNoErr != res) { |
| res = kEpidBadArgErr; |
| break; |
| } |
| res = ReadEcPoint(G3, &(sigrl_entry->b), sizeof(sigrl_entry->b), B_tick); |
| if (kEpidNoErr != res) { |
| res = kEpidBadArgErr; |
| break; |
| } |
| { |
| EcPoint const* points[3]; |
| BigNum const* exponents[3]; |
| points[0] = K_tick; |
| points[1] = B_tick; |
| points[2] = T; |
| exponents[0] = smu; |
| exponents[1] = snu; |
| exponents[2] = nc_tick_bn; |
| res = EcMultiExpBn(G3, points, exponents, COUNT_OF(points), R2); |
| BREAK_ON_EPID_ERROR(res); |
| } |
| // 8. The verifier verifies c = Hash(p' || g3 || B || K || B' || K' || T || |
| // R1 || R2 || mSize || m). |
| if (msg) { |
| // Memory copy is used to copy a message of variable length |
| if (0 != memcpy_S(&commit_values->msg[0], msg_len, msg, msg_len)) { |
| res = kEpidBadArgErr; |
| break; |
| } |
| } |
| commit_values->g3 = ctx->commit_values.g3; |
| commit_values->B = sig->B; |
| commit_values->K = sig->K; |
| commit_values->B_tick = sigrl_entry->b; |
| commit_values->K_tick = sigrl_entry->k; |
| commit_values->T = proof->T; |
| commit_values->msg_len = ntohl(msg_len); |
| res = WriteEcPoint(G3, R1, &commit_values->R1, sizeof(commit_values->R1)); |
| BREAK_ON_EPID_ERROR(res); |
| res = WriteEcPoint(G3, R2, &commit_values->R2, sizeof(commit_values->R2)); |
| BREAK_ON_EPID_ERROR(res); |
| res = Sha256MessageDigest(commit_values, commit_len, &commit_hash); |
| if (0 != memcmp(&proof->c, &commit_hash, sizeof(proof->c))) { |
| res = kEpidBadArgErr; |
| break; |
| } |
| } while (0); |
| SAFE_FREE(commit_values); |
| DeleteEcPoint(&T); |
| DeleteEcPoint(&R1); |
| DeleteEcPoint(&R2); |
| |
| DeleteEcPoint(&K); |
| DeleteEcPoint(&B); |
| DeleteEcPoint(&K_tick); |
| DeleteEcPoint(&B_tick); |
| |
| DeleteBigNum(&smu); |
| DeleteBigNum(&snu); |
| |
| DeleteBigNum(&nc_tick_bn); |
| |
| return res; |
| } |