Home | History | Annotate | Download | only in src
      1 /*############################################################################
      2   # Copyright 2016-2017 Intel Corporation
      3   #
      4   # Licensed under the Apache License, Version 2.0 (the "License");
      5   # you may not use this file except in compliance with the License.
      6   # You may obtain a copy of the License at
      7   #
      8   #     http://www.apache.org/licenses/LICENSE-2.0
      9   #
     10   # Unless required by applicable law or agreed to in writing, software
     11   # distributed under the License is distributed on an "AS IS" BASIS,
     12   # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13   # See the License for the specific language governing permissions and
     14   # limitations under the License.
     15   ############################################################################*/
     16 
     17 /*!
     18  * \file
     19  * \brief EcdsaVerifyBuffer implementation.
     20  */
     21 
     22 #include "epid/common/math/ecdsa.h"
     23 
     24 #include "epid/common/math/bignum.h"
     25 #include "epid/common/math/src/bignum-internal.h"
     26 #include "epid/common/src/memory.h"
     27 #include "ext/ipp/include/ippcp.h"
     28 
     29 /// Handle Ipp Errors with Break
     30 #define BREAK_ON_IPP_ERROR(sts, ret) \
     31   {                                  \
     32     IppStatus temp_sts = (sts);      \
     33     if (ippStsNoErr != temp_sts) {   \
     34       (ret) = kEpidMathErr;          \
     35       break;                         \
     36     }                                \
     37   }
     38 
     39 static EpidStatus NewSecp256r1Curve(IppsECCPState** ec);
     40 
     41 static void DeleteSecp256r1Curve(IppsECCPState** ec);
     42 
     43 static EpidStatus NewCurvePoint(IppsECCPState const* ec,
     44                                 IppsECCPPointState** p);
     45 
     46 static EpidStatus ReadCurvePoint(IppsECCPState* ec,
     47                                  EcdsaPublicKey const* pubkey,
     48                                  IppsECCPPointState* p);
     49 
     50 static EpidStatus CalcHashBn(ConstOctStr buf, size_t buf_len,
     51                              BigNum* bn_digest);
     52 
     53 static void DeleteCurvePoint(IppsECCPPointState** p);
     54 
     55 static EpidStatus ValidateSignature(BigNum const* bn_sig_x,
     56                                     BigNum const* bn_sig_y);
     57 
     58 EpidStatus EcdsaVerifyBuffer(ConstOctStr buf, size_t buf_len,
     59                              EcdsaPublicKey const* pubkey,
     60                              EcdsaSignature const* sig) {
     61   EpidStatus result = kEpidErr;
     62   IppsECCPState* ec_state = NULL;
     63   IppsECCPPointState* ecp_pubkey = NULL;
     64   BigNum* bn_sig_x = NULL;
     65   BigNum* bn_sig_y = NULL;
     66   BigNum* bn_digest = NULL;
     67 
     68   if (!pubkey || !sig || (!buf && (0 != buf_len))) return kEpidBadArgErr;
     69   if (INT_MAX < buf_len) return kEpidBadArgErr;
     70 
     71   do {
     72     EpidStatus epid_status = kEpidNoErr;
     73     IppStatus ipp_status = ippStsNoErr;
     74     IppECResult ec_result = ippECValid;
     75 
     76     epid_status = NewBigNum(sizeof(sig->x), &bn_sig_x);
     77     if (kEpidNoErr != epid_status) break;
     78 
     79     epid_status = ReadBigNum(&sig->x, sizeof(sig->x), bn_sig_x);
     80     if (kEpidNoErr != epid_status) break;
     81 
     82     epid_status = NewBigNum(sizeof(sig->y), &bn_sig_y);
     83     if (kEpidNoErr != epid_status) break;
     84 
     85     epid_status = ReadBigNum(&sig->y, sizeof(sig->y), bn_sig_y);
     86     if (kEpidNoErr != epid_status) break;
     87 
     88     // check for invalid signature
     89     epid_status = ValidateSignature(bn_sig_x, bn_sig_y);
     90     if (kEpidSigValid != epid_status) {
     91       if (kEpidSigInvalid == epid_status) {
     92         result = kEpidBadArgErr;
     93       } else {
     94         result = epid_status;
     95       }
     96       break;
     97     }
     98 
     99     // setup curve
    100     epid_status = NewSecp256r1Curve(&ec_state);
    101     if (kEpidNoErr != epid_status) break;
    102 
    103     // load pubkey
    104     epid_status = NewCurvePoint(ec_state, &ecp_pubkey);
    105     if (kEpidNoErr != epid_status) break;
    106     epid_status = ReadCurvePoint(ec_state, pubkey, ecp_pubkey);
    107     if (kEpidBadArgErr == epid_status) {
    108       result = kEpidBadArgErr;
    109       break;
    110     } else if (kEpidNoErr != epid_status) {
    111       break;
    112     }
    113 
    114     // check for invalid pubkey
    115     ipp_status = ippsECCPCheckPoint(ecp_pubkey, &ec_result, ec_state);
    116     BREAK_ON_IPP_ERROR(ipp_status, result);
    117     if (ippECValid != ec_result) {
    118       result = kEpidBadArgErr;
    119       break;
    120     }
    121 
    122     // hash message
    123     epid_status = NewBigNum(IPP_SHA256_DIGEST_BITSIZE / 8, &bn_digest);
    124     if (kEpidNoErr != epid_status) break;
    125     epid_status = CalcHashBn(buf, buf_len, bn_digest);
    126     if (kEpidNoErr != epid_status) break;
    127 
    128     // configure key
    129     ipp_status = ippsECCPSetKeyPair(NULL, ecp_pubkey, ippTrue, ec_state);
    130     BREAK_ON_IPP_ERROR(ipp_status, result);
    131 
    132     // verify message
    133     ipp_status = ippsECCPVerifyDSA(bn_digest->ipp_bn, bn_sig_x->ipp_bn,
    134                                    bn_sig_y->ipp_bn, &ec_result, ec_state);
    135     BREAK_ON_IPP_ERROR(ipp_status, result);
    136 
    137     if (ippECValid == ec_result)
    138       result = kEpidSigValid;
    139     else
    140       result = kEpidSigInvalid;
    141   } while (0);
    142 
    143   DeleteSecp256r1Curve(&ec_state);
    144   DeleteCurvePoint(&ecp_pubkey);
    145   DeleteBigNum(&bn_digest);
    146   DeleteBigNum(&bn_sig_x);
    147   DeleteBigNum(&bn_sig_y);
    148 
    149   return result;
    150 }
    151 
    152 static EpidStatus NewSecp256r1Curve(IppsECCPState** ec) {
    153   EpidStatus result = kEpidNoErr;
    154   IppsECCPState* ec_state = NULL;
    155 
    156   if (!ec) return kEpidBadArgErr;
    157 
    158   do {
    159     int size = 0;
    160     IppStatus ipp_status = ippStsNoErr;
    161     ipp_status = ippsECCPGetSizeStd256r1(&size);
    162     BREAK_ON_IPP_ERROR(ipp_status, result);
    163 
    164     ec_state = (IppsECCPState*)SAFE_ALLOC(size);
    165     if (!ec_state) {
    166       result = kEpidMemAllocErr;
    167       break;
    168     }
    169 
    170     ipp_status = ippsECCPInitStd256r1(ec_state);
    171     BREAK_ON_IPP_ERROR(ipp_status, result);
    172 
    173     ipp_status = ippsECCPSetStd256r1(ec_state);
    174     BREAK_ON_IPP_ERROR(ipp_status, result);
    175 
    176     *ec = ec_state;
    177   } while (0);
    178   if (kEpidNoErr != result) {
    179     SAFE_FREE(ec_state);
    180   }
    181   return result;
    182 }
    183 
    184 static void DeleteSecp256r1Curve(IppsECCPState** ec) {
    185   if (!ec || !(*ec)) {
    186     return;
    187   }
    188   SAFE_FREE(*ec);
    189   *ec = NULL;
    190 }
    191 
    192 static EpidStatus NewCurvePoint(IppsECCPState const* ec,
    193                                 IppsECCPPointState** p) {
    194   EpidStatus result = kEpidNoErr;
    195   IppsECCPPointState* point = NULL;
    196 
    197   if (!ec || !p) return kEpidBadArgErr;
    198 
    199   do {
    200     const int kFeBitSize = 256;
    201     IppStatus ipp_status = ippStsNoErr;
    202     int size = 0;
    203 
    204     ipp_status = ippsECCPPointGetSize(kFeBitSize, &size);
    205     BREAK_ON_IPP_ERROR(ipp_status, result);
    206 
    207     point = (IppsECCPPointState*)SAFE_ALLOC(size);
    208     if (!point) {
    209       result = kEpidMemAllocErr;
    210       break;
    211     }
    212 
    213     ipp_status = ippsECCPPointInit(kFeBitSize, point);
    214     BREAK_ON_IPP_ERROR(ipp_status, result);
    215 
    216     *p = point;
    217   } while (0);
    218   if (kEpidNoErr != result) {
    219     SAFE_FREE(point);
    220   }
    221   return result;
    222 }
    223 static void DeleteCurvePoint(IppsECCPPointState** p) {
    224   if (!p || !(*p)) {
    225     return;
    226   }
    227   SAFE_FREE(*p);
    228   *p = NULL;
    229 }
    230 
    231 static EpidStatus ReadCurvePoint(IppsECCPState* ec,
    232                                  EcdsaPublicKey const* pubkey,
    233                                  IppsECCPPointState* p) {
    234   EpidStatus result = kEpidNoErr;
    235   BigNum* bn_pubkey_x = NULL;
    236   BigNum* bn_pubkey_y = NULL;
    237 
    238   if (!ec || !pubkey || !p) return kEpidBadArgErr;
    239 
    240   do {
    241     IppStatus ipp_status = ippStsNoErr;
    242 
    243     result = NewBigNum(sizeof(pubkey->x), &bn_pubkey_x);
    244     if (kEpidNoErr != result) break;
    245 
    246     result = ReadBigNum(&pubkey->x, sizeof(pubkey->x), bn_pubkey_x);
    247     if (kEpidNoErr != result) break;
    248 
    249     result = NewBigNum(sizeof(pubkey->y), &bn_pubkey_y);
    250     if (kEpidNoErr != result) break;
    251 
    252     result = ReadBigNum(&pubkey->y, sizeof(pubkey->y), bn_pubkey_y);
    253     if (kEpidNoErr != result) break;
    254 
    255     ipp_status =
    256         ippsECCPSetPoint(bn_pubkey_x->ipp_bn, bn_pubkey_y->ipp_bn, p, ec);
    257     if (ipp_status == ippStsOutOfRangeErr) {
    258       result = kEpidBadArgErr;
    259       break;
    260     } else if (ipp_status != ippStsNoErr) {
    261       result = kEpidMathErr;
    262       break;
    263     }
    264   } while (0);
    265 
    266   DeleteBigNum(&bn_pubkey_x);
    267   DeleteBigNum(&bn_pubkey_y);
    268 
    269   return result;
    270 }
    271 
    272 static EpidStatus CalcHashBn(ConstOctStr buf, size_t buf_len,
    273                              BigNum* bn_digest) {
    274   EpidStatus result = kEpidErr;
    275   BigNum* bn_ec_order = NULL;
    276 
    277   if (!bn_digest || (!buf && (0 != buf_len))) return kEpidBadArgErr;
    278 
    279   do {
    280     IppStatus ipp_status = ippStsNoErr;
    281     Ipp8u digest[IPP_SHA256_DIGEST_BITSIZE / 8] = {0};
    282 
    283     const uint8_t secp256r1_r[] = {
    284         0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
    285         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBC, 0xE6, 0xFA, 0xAD, 0xA7, 0x17,
    286         0x9E, 0x84, 0xF3, 0xB9, 0xCA, 0xC2, 0xFC, 0x63, 0x25, 0x51};
    287 
    288     ipp_status = ippsSHA256MessageDigest(buf, (int)buf_len, digest);
    289     BREAK_ON_IPP_ERROR(ipp_status, result);
    290 
    291     // convert hash to BigNum for use by ipp
    292     result = ReadBigNum(digest, sizeof(digest), bn_digest);
    293     if (kEpidNoErr != result) break;
    294 
    295     result = NewBigNum(sizeof(secp256r1_r), &bn_ec_order);
    296     if (kEpidNoErr != result) break;
    297 
    298     result = ReadBigNum(secp256r1_r, sizeof(secp256r1_r), bn_ec_order);
    299     if (kEpidNoErr != result) break;
    300 
    301     ipp_status =
    302         ippsMod_BN(bn_digest->ipp_bn, bn_ec_order->ipp_bn, bn_digest->ipp_bn);
    303     BREAK_ON_IPP_ERROR(ipp_status, result);
    304 
    305     result = kEpidNoErr;
    306   } while (0);
    307 
    308   DeleteBigNum(&bn_ec_order);
    309 
    310   return result;
    311 }
    312 
    313 static EpidStatus ValidateSignature(BigNum const* bn_sig_x,
    314                                     BigNum const* bn_sig_y) {
    315   EpidStatus result = kEpidSigInvalid;
    316 
    317   BigNum* bn_ec_order = NULL;
    318 
    319   if (!bn_sig_x || !bn_sig_y) return kEpidBadArgErr;
    320 
    321   do {
    322     IppStatus ipp_status = ippStsNoErr;
    323     Ipp32u sig_x_cmp0 = IS_ZERO;
    324     Ipp32u sig_y_cmp0 = IS_ZERO;
    325     Ipp32u sig_x_cmp_order = IS_ZERO;
    326     Ipp32u sig_y_cmp_order = IS_ZERO;
    327     const uint8_t secp256r1_r[] = {
    328         0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
    329         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBC, 0xE6, 0xFA, 0xAD, 0xA7, 0x17,
    330         0x9E, 0x84, 0xF3, 0xB9, 0xCA, 0xC2, 0xFC, 0x63, 0x25, 0x51};
    331 
    332     result = NewBigNum(sizeof(secp256r1_r), &bn_ec_order);
    333     if (kEpidNoErr != result) break;
    334 
    335     result = ReadBigNum(secp256r1_r, sizeof(secp256r1_r), bn_ec_order);
    336     if (kEpidNoErr != result) break;
    337 
    338     ipp_status = ippsCmpZero_BN(bn_sig_x->ipp_bn, &sig_x_cmp0);
    339     BREAK_ON_IPP_ERROR(ipp_status, result);
    340     ipp_status = ippsCmpZero_BN(bn_sig_y->ipp_bn, &sig_y_cmp0);
    341     BREAK_ON_IPP_ERROR(ipp_status, result);
    342     ipp_status =
    343         ippsCmp_BN(bn_sig_x->ipp_bn, bn_ec_order->ipp_bn, &sig_x_cmp_order);
    344     BREAK_ON_IPP_ERROR(ipp_status, result);
    345     ipp_status =
    346         ippsCmp_BN(bn_sig_y->ipp_bn, bn_ec_order->ipp_bn, &sig_y_cmp_order);
    347     BREAK_ON_IPP_ERROR(ipp_status, result);
    348 
    349     if (IS_ZERO == sig_x_cmp0 || IS_ZERO == sig_y_cmp0 ||
    350         LESS_THAN_ZERO != sig_x_cmp_order ||
    351         LESS_THAN_ZERO != sig_y_cmp_order) {
    352       result = kEpidSigInvalid;
    353       break;
    354     } else {
    355       result = kEpidSigValid;
    356     }
    357   } while (0);
    358 
    359   DeleteBigNum(&bn_ec_order);
    360 
    361   return result;
    362 }
    363