• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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