Fix minor sign API errors. Fix documentation.
[platform/core/security/yaca.git] / src / sign.c
1 /*
2  *  Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Contact: Krzysztof Jackiewicz <k.jackiewicz@samsung.com>
5  *
6  *  Licensed under the Apache License, Version 2.0 (the "License");
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License
17  */
18
19 /**
20  * @file sign.c
21  * @brief
22  */
23
24 #include <assert.h>
25 #include <string.h>
26
27 #include <openssl/evp.h>
28 #include <openssl/rsa.h>
29 #include <openssl/cmac.h>
30
31 #include <yaca_crypto.h>
32 #include <yaca_sign.h>
33 #include <yaca_error.h>
34 #include <yaca_key.h>
35
36 #include "internal.h"
37
38 /* Operation type saved in context to recognize what
39  * type of operation is performed and how to perform it.
40  */
41 enum sign_op_type {
42         OP_SIGN = 0,
43         OP_VERIFY = 1
44 };
45
46 struct yaca_sign_context_s {
47         struct yaca_context_s ctx;
48
49         EVP_MD_CTX *md_ctx;
50         enum sign_op_type op_type;
51         enum context_state_e state;
52 };
53
54 static bool CTX_DEFAULT_STATES[CTX_COUNT][CTX_COUNT] = {
55 /* from \ to  INIT, MSG, FIN */
56 /* INIT */  { 0,    1,    1 },
57 /* MSG  */  { 0,    1,    1 },
58 /* FIN  */  { 0,    0,    0 },
59 };
60
61 static bool verify_state_change(struct yaca_sign_context_s *c, enum context_state_e to)
62 {
63         int from = c->state;
64
65         return CTX_DEFAULT_STATES[from][to];
66 }
67
68 static struct yaca_sign_context_s *get_sign_context(const yaca_context_h ctx)
69 {
70         if (ctx == YACA_CONTEXT_NULL)
71                 return NULL;
72
73         switch (ctx->type) {
74         case YACA_CONTEXT_SIGN:
75                 return (struct yaca_sign_context_s *)ctx;
76         default:
77                 return NULL;
78         }
79 }
80
81 static int get_sign_output_length(const yaca_context_h ctx,
82                                   size_t input_len,
83                                   size_t *output_len)
84 {
85         assert(output_len != NULL);
86
87         struct yaca_sign_context_s *c = get_sign_context(ctx);
88         EVP_PKEY_CTX *pctx;
89
90         if (c == NULL || input_len != 0)
91                 return YACA_ERROR_INVALID_PARAMETER;
92
93         assert(c->md_ctx != NULL);
94
95         pctx = EVP_MD_CTX_pkey_ctx(c->md_ctx);
96         if (pctx == NULL)
97                 return YACA_ERROR_INTERNAL;
98
99         EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(pctx);
100         if (pkey == NULL) {
101                 ERROR_DUMP(YACA_ERROR_INTERNAL);
102                 return YACA_ERROR_INTERNAL;
103         }
104
105         int len = EVP_PKEY_size(pkey);
106         if (len <= 0) {
107                 ERROR_DUMP(YACA_ERROR_INTERNAL);
108                 return YACA_ERROR_INTERNAL;
109         }
110
111         *output_len = len;
112         return YACA_ERROR_NONE;
113 }
114
115 static void destroy_sign_context(yaca_context_h ctx)
116 {
117         struct yaca_sign_context_s *c = get_sign_context(ctx);
118
119         if (c == NULL)
120                 return;
121
122         EVP_MD_CTX_destroy(c->md_ctx);
123         c->md_ctx = NULL;
124 }
125
126 int set_sign_property(yaca_context_h ctx,
127                       yaca_property_e property,
128                       const void *value,
129                       size_t value_len)
130 {
131         int ret;
132         struct yaca_sign_context_s *c = get_sign_context(ctx);
133         yaca_padding_e padding;
134         int pad;
135         EVP_PKEY *pkey;
136         EVP_PKEY_CTX *pctx;
137
138         if (c == NULL || value == NULL || c->state == CTX_FINALIZED)
139                 return YACA_ERROR_INVALID_PARAMETER;
140
141         assert(c->md_ctx != NULL);
142
143         pctx = EVP_MD_CTX_pkey_ctx(c->md_ctx);
144         if (pctx == NULL)
145                 return YACA_ERROR_INTERNAL;
146
147         /* this function only supports padding */
148         if (property != YACA_PROPERTY_PADDING || value_len != sizeof(yaca_padding_e))
149                 return YACA_ERROR_INVALID_PARAMETER;
150
151         padding = *(yaca_padding_e *)(value);
152
153         switch (padding) {
154         case YACA_PADDING_X931:
155         case YACA_PADDING_PKCS1:
156         case YACA_PADDING_PKCS1_PSS:
157                 break;
158         default:
159                 return YACA_ERROR_INVALID_PARAMETER;
160         }
161
162         pad = rsa_padding2openssl(padding);
163         assert(pad != -1);
164
165         pkey = EVP_PKEY_CTX_get0_pkey(pctx);
166         if (pkey == NULL) {
167                 ret = YACA_ERROR_INTERNAL;
168                 ERROR_DUMP(ret);
169                 return ret;
170         }
171
172         /* padding only works for RSA */
173         if (EVP_PKEY_id(pkey) != EVP_PKEY_RSA)
174                 return YACA_ERROR_INVALID_PARAMETER;
175
176         ret = EVP_PKEY_CTX_set_rsa_padding(pctx, pad);
177         if (ret <= 0) {
178                 ret = ERROR_HANDLE();
179                 return ret;
180         }
181
182         return YACA_ERROR_NONE;
183 }
184
185 API int yaca_sign_initialize(yaca_context_h *ctx,
186                              yaca_digest_algorithm_e algo,
187                              const yaca_key_h prv_key)
188 {
189         struct yaca_sign_context_s *nc = NULL;
190         const EVP_MD *md = NULL;
191         int ret;
192         const struct yaca_key_evp_s *evp_key = key_get_evp(prv_key);
193
194         if (ctx == NULL || evp_key == NULL)
195                 return YACA_ERROR_INVALID_PARAMETER;
196
197         ret = digest_get_algorithm(algo, &md);
198         if (ret != YACA_ERROR_NONE)
199                 return ret;
200
201         switch (prv_key->type) {
202         case YACA_KEY_TYPE_RSA_PRIV:
203                 if (EVP_MD_size(md) >= EVP_PKEY_size(evp_key->evp) ||
204                     (algo == YACA_DIGEST_SHA384 && (EVP_PKEY_size(evp_key->evp) <= YACA_KEY_LENGTH_512BIT / 8)))
205                         return YACA_ERROR_INVALID_PARAMETER;
206                 break;
207         case YACA_KEY_TYPE_DSA_PRIV:
208         case YACA_KEY_TYPE_EC_PRIV:
209                 break;
210         default:
211                 return YACA_ERROR_INVALID_PARAMETER;
212         }
213
214         ret = yaca_zalloc(sizeof(struct yaca_sign_context_s), (void**)&nc);
215         if (ret != YACA_ERROR_NONE)
216                 return ret;
217
218         nc->op_type = OP_SIGN;
219         nc->ctx.type = YACA_CONTEXT_SIGN;
220         nc->ctx.context_destroy = destroy_sign_context;
221         nc->ctx.get_output_length = get_sign_output_length;
222         nc->ctx.set_property = set_sign_property;
223         nc->ctx.get_property = NULL;
224
225         nc->md_ctx = EVP_MD_CTX_create();
226         if (nc->md_ctx == NULL) {
227                 ret = YACA_ERROR_INTERNAL;
228                 ERROR_DUMP(ret);
229                 goto exit;
230         }
231
232         ret = EVP_DigestSignInit(nc->md_ctx, NULL, md, NULL, evp_key->evp);
233         if (ret != 1) {
234                 ret = ERROR_HANDLE();
235                 goto exit;
236         }
237
238         nc->state = CTX_INITIALIZED;
239         *ctx = (yaca_context_h)nc;
240         nc = NULL;
241         ret = YACA_ERROR_NONE;
242
243 exit:
244         yaca_context_destroy((yaca_context_h)nc);
245
246         return ret;
247 }
248
249 API int yaca_sign_initialize_hmac(yaca_context_h *ctx,
250                                   yaca_digest_algorithm_e algo,
251                                   const yaca_key_h sym_key)
252 {
253         struct yaca_sign_context_s *nc = NULL;
254         EVP_PKEY *pkey = NULL;
255         const EVP_MD *md;
256         int ret;
257         const struct yaca_key_simple_s *simple_key = key_get_simple(sym_key);
258
259         if (ctx == NULL || simple_key == NULL ||
260             (sym_key->type != YACA_KEY_TYPE_SYMMETRIC && sym_key->type != YACA_KEY_TYPE_DES))
261                 return YACA_ERROR_INVALID_PARAMETER;
262
263         ret = yaca_zalloc(sizeof(struct yaca_sign_context_s), (void**)&nc);
264         if (ret != YACA_ERROR_NONE)
265                 return ret;
266
267         nc->op_type = OP_SIGN;
268         nc->ctx.type = YACA_CONTEXT_SIGN;
269         nc->ctx.context_destroy = destroy_sign_context;
270         nc->ctx.get_output_length = get_sign_output_length;
271         nc->ctx.set_property = NULL;
272         nc->ctx.get_property = NULL;
273
274         pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC,
275                                     NULL,
276                                     (unsigned char *)simple_key->d,
277                                     simple_key->bit_len / 8);
278         if (pkey == NULL) {
279                 ret = YACA_ERROR_INTERNAL;
280                 ERROR_DUMP(ret);
281                 goto exit;
282         }
283
284         ret = digest_get_algorithm(algo, &md);
285         if (ret != YACA_ERROR_NONE)
286                 goto exit;
287
288         nc->md_ctx = EVP_MD_CTX_create();
289         if (nc->md_ctx == NULL) {
290                 ret = YACA_ERROR_INTERNAL;
291                 ERROR_DUMP(ret);
292                 goto exit;
293         }
294
295         ret = EVP_DigestSignInit(nc->md_ctx, NULL, md, NULL, pkey);
296         if (ret != 1) {
297                 ret = YACA_ERROR_INTERNAL;
298                 ERROR_DUMP(ret);
299                 goto exit;
300         }
301
302         nc->state = CTX_INITIALIZED;
303         *ctx = (yaca_context_h)nc;
304         nc = NULL;
305         ret = YACA_ERROR_NONE;
306
307 exit:
308         EVP_PKEY_free(pkey);
309         yaca_context_destroy((yaca_context_h)nc);
310
311         return ret;
312 }
313
314 API int yaca_sign_initialize_cmac(yaca_context_h *ctx,
315                                   yaca_encrypt_algorithm_e algo,
316                                   const yaca_key_h sym_key)
317 {
318         struct yaca_sign_context_s *nc = NULL;
319         CMAC_CTX* cmac_ctx = NULL;
320         const EVP_CIPHER* cipher = NULL;
321         EVP_PKEY *pkey = NULL;
322         int ret;
323         const struct yaca_key_simple_s *simple_key = key_get_simple(sym_key);
324
325         if (ctx == NULL || simple_key == NULL ||
326             (sym_key->type != YACA_KEY_TYPE_SYMMETRIC && sym_key->type != YACA_KEY_TYPE_DES))
327                 return YACA_ERROR_INVALID_PARAMETER;
328
329         ret = yaca_zalloc(sizeof(struct yaca_sign_context_s), (void**)&nc);
330         if (ret != YACA_ERROR_NONE)
331                 return ret;
332
333         nc->op_type = OP_SIGN;
334         nc->ctx.type = YACA_CONTEXT_SIGN;
335         nc->ctx.context_destroy = destroy_sign_context;
336         nc->ctx.get_output_length = get_sign_output_length;
337         nc->ctx.set_property = NULL;
338         nc->ctx.get_property = NULL;
339
340         ret = encrypt_get_algorithm(algo, YACA_BCM_CBC, simple_key->bit_len, &cipher);
341         if (ret != YACA_ERROR_NONE)
342                 goto exit;
343
344         /* create and initialize low level CMAC context */
345         cmac_ctx = CMAC_CTX_new();
346         if (cmac_ctx == NULL) {
347                 ret = YACA_ERROR_INTERNAL;
348                 ERROR_DUMP(ret);
349                 goto exit;
350         }
351
352         if (CMAC_Init(cmac_ctx, simple_key->d, simple_key->bit_len / 8, cipher, NULL) != 1) {
353                 ret = YACA_ERROR_INTERNAL;
354                 ERROR_DUMP(ret);
355                 goto exit;
356         }
357
358         /* create key and assign CMAC context to it */
359         pkey = EVP_PKEY_new();
360         if (pkey == NULL) {
361                 ret = YACA_ERROR_INTERNAL;
362                 ERROR_DUMP(ret);
363                 goto exit;
364         }
365
366         if (EVP_PKEY_assign(pkey, EVP_PKEY_CMAC, cmac_ctx) != 1) {
367                 ret = YACA_ERROR_INTERNAL;
368                 ERROR_DUMP(ret);
369                 goto exit;
370         }
371
372         cmac_ctx = NULL;
373
374         nc->md_ctx = EVP_MD_CTX_create();
375         if (nc->md_ctx == NULL) {
376                 ret = YACA_ERROR_INTERNAL;
377                 ERROR_DUMP(ret);
378                 goto exit;
379         }
380
381         if (EVP_DigestSignInit(nc->md_ctx, NULL, NULL, NULL, pkey) != 1) {
382                 ret = YACA_ERROR_INTERNAL;
383                 ERROR_DUMP(ret);
384                 goto exit;
385         }
386
387         nc->state = CTX_INITIALIZED;
388         *ctx = (yaca_context_h)nc;
389         nc = NULL;
390         ret = YACA_ERROR_NONE;
391
392 exit:
393         EVP_PKEY_free(pkey);
394         CMAC_CTX_free(cmac_ctx);
395         yaca_context_destroy((yaca_context_h)nc);
396
397         return ret;
398 }
399
400 API int yaca_sign_update(yaca_context_h ctx,
401                          const char *message,
402                          size_t message_len)
403 {
404         struct yaca_sign_context_s *c = get_sign_context(ctx);
405         int ret;
406
407         if (c == NULL || c->op_type != OP_SIGN ||
408             message == NULL || message_len == 0)
409                 return YACA_ERROR_INVALID_PARAMETER;
410
411         if (!verify_state_change(c, CTX_MSG_UPDATED))
412                 return YACA_ERROR_INVALID_PARAMETER;
413
414         ret = EVP_DigestSignUpdate(c->md_ctx, message, message_len);
415         if (ret != 1) {
416                 ret = YACA_ERROR_INTERNAL;
417                 ERROR_DUMP(ret);
418                 return ret;
419         }
420
421         c->state = CTX_MSG_UPDATED;
422         return YACA_ERROR_NONE;
423 }
424
425 API int yaca_sign_finalize(yaca_context_h ctx,
426                            char *signature,
427                            size_t *signature_len)
428 {
429         struct yaca_sign_context_s *c = get_sign_context(ctx);
430         int ret;
431
432         if (c == NULL ||  c->op_type != OP_SIGN ||
433             signature == NULL || signature_len == NULL || *signature_len == 0)
434                 return YACA_ERROR_INVALID_PARAMETER;
435
436         if (!verify_state_change(c, CTX_FINALIZED))
437                 return YACA_ERROR_INVALID_PARAMETER;
438
439         ret = EVP_DigestSignFinal(c->md_ctx, (unsigned char *)signature, signature_len);
440         if (ret != 1) {
441                 ret = YACA_ERROR_INTERNAL;
442                 ERROR_DUMP(ret);
443                 return ret;
444         }
445
446         c->state = CTX_FINALIZED;
447         return YACA_ERROR_NONE;
448 }
449
450 API int yaca_verify_initialize(yaca_context_h *ctx,
451                                yaca_digest_algorithm_e algo,
452                                const yaca_key_h pub_key)
453 {
454         struct yaca_sign_context_s *nc = NULL;
455         const EVP_MD *md = NULL;
456         int ret;
457         const struct yaca_key_evp_s *evp_key = key_get_evp(pub_key);
458
459         if (ctx == NULL || evp_key == NULL)
460                 return YACA_ERROR_INVALID_PARAMETER;
461
462         ret = digest_get_algorithm(algo, &md);
463         if (ret != YACA_ERROR_NONE)
464                 return ret;
465
466         switch (pub_key->type) {
467         case YACA_KEY_TYPE_RSA_PUB:
468                 if (EVP_MD_size(md) >= EVP_PKEY_size(evp_key->evp) ||
469                     (algo == YACA_DIGEST_SHA384 && (EVP_PKEY_size(evp_key->evp) <= YACA_KEY_LENGTH_512BIT / 8)))
470                         return YACA_ERROR_INVALID_PARAMETER;
471                 break;
472         case YACA_KEY_TYPE_DSA_PUB:
473         case YACA_KEY_TYPE_EC_PUB:
474                 break;
475         default:
476                 return YACA_ERROR_INVALID_PARAMETER;
477         }
478
479         ret = yaca_zalloc(sizeof(struct yaca_sign_context_s), (void**)&nc);
480         if (ret != YACA_ERROR_NONE)
481                 return ret;
482
483         nc->op_type = OP_VERIFY;
484         nc->ctx.type = YACA_CONTEXT_SIGN;
485         nc->ctx.context_destroy = destroy_sign_context;
486         nc->ctx.get_output_length = NULL;
487         nc->ctx.set_property = set_sign_property;
488         nc->ctx.get_property = NULL;
489
490         nc->md_ctx = EVP_MD_CTX_create();
491         if (nc->md_ctx == NULL) {
492                 ret = YACA_ERROR_INTERNAL;
493                 ERROR_DUMP(ret);
494                 goto exit;
495         }
496
497         ret = EVP_DigestVerifyInit(nc->md_ctx, NULL, md, NULL, evp_key->evp);
498         if (ret != 1) {
499                 ret = ERROR_HANDLE();
500                 goto exit;
501         }
502
503         nc->state = CTX_INITIALIZED;
504         *ctx = (yaca_context_h)nc;
505         nc = NULL;
506         ret = YACA_ERROR_NONE;
507
508 exit:
509         yaca_context_destroy((yaca_context_h)nc);
510
511         return ret;
512 }
513
514 API int yaca_verify_update(yaca_context_h ctx,
515                            const char *message,
516                            size_t message_len)
517 {
518         struct yaca_sign_context_s *c = get_sign_context(ctx);
519         int ret;
520
521         if (c == NULL || message == NULL || message_len == 0 || c->op_type != OP_VERIFY)
522                 return YACA_ERROR_INVALID_PARAMETER;
523
524         if (!verify_state_change(c, CTX_MSG_UPDATED))
525                 return YACA_ERROR_INVALID_PARAMETER;
526
527         ret = EVP_DigestVerifyUpdate(c->md_ctx, message, message_len);
528         if (ret != 1) {
529                 ret = YACA_ERROR_INTERNAL;
530                 ERROR_DUMP(ret);
531                 return ret;
532         }
533
534         c->state = CTX_MSG_UPDATED;
535         return YACA_ERROR_NONE;
536 }
537
538 API int yaca_verify_finalize(yaca_context_h ctx,
539                              const char *signature,
540                              size_t signature_len)
541 {
542         struct yaca_sign_context_s *c = get_sign_context(ctx);
543         int ret;
544
545         if (c == NULL || signature == NULL || signature_len == 0 || c->op_type != OP_VERIFY)
546                 return YACA_ERROR_INVALID_PARAMETER;
547
548         if (!verify_state_change(c, CTX_FINALIZED))
549                 return YACA_ERROR_INVALID_PARAMETER;
550
551         ret = EVP_DigestVerifyFinal(c->md_ctx,
552                                     (unsigned char *)signature,
553                                     signature_len);
554
555         if (ret == 1) {
556                 c->state = CTX_FINALIZED;
557                 return YACA_ERROR_NONE;
558         }
559
560         if (ret == 0) {
561                 ERROR_CLEAR();
562                 return YACA_ERROR_DATA_MISMATCH;
563         }
564
565         ret = YACA_ERROR_INTERNAL;
566         ERROR_DUMP(ret);
567         return ret;
568 }