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