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
EcdsaVerifyBuffer(ConstOctStr buf,size_t buf_len,EcdsaPublicKey const * pubkey,EcdsaSignature const * sig)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
NewSecp256r1Curve(IppsECCPState ** ec)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
DeleteSecp256r1Curve(IppsECCPState ** ec)184 static void DeleteSecp256r1Curve(IppsECCPState** ec) {
185 if (!ec || !(*ec)) {
186 return;
187 }
188 SAFE_FREE(*ec);
189 *ec = NULL;
190 }
191
NewCurvePoint(IppsECCPState const * ec,IppsECCPPointState ** p)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 }
DeleteCurvePoint(IppsECCPPointState ** p)223 static void DeleteCurvePoint(IppsECCPPointState** p) {
224 if (!p || !(*p)) {
225 return;
226 }
227 SAFE_FREE(*p);
228 *p = NULL;
229 }
230
ReadCurvePoint(IppsECCPState * ec,EcdsaPublicKey const * pubkey,IppsECCPPointState * p)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
CalcHashBn(ConstOctStr buf,size_t buf_len,BigNum * bn_digest)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
ValidateSignature(BigNum const * bn_sig_x,BigNum const * bn_sig_y)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