Replace spaces with tabs
[platform/core/security/yaca.git] / src / digest.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 digest.c
21  * @brief
22  */
23
24 #include <assert.h>
25
26 #include <openssl/evp.h>
27
28 #include <yaca_crypto.h>
29 #include <yaca_digest.h>
30 #include <yaca_error.h>
31
32 #include "internal.h"
33
34 static const struct {
35         yaca_digest_algorithm_e algo;
36         const EVP_MD *(*digest)(void);
37 } MESSAGE_DIGESTS[] = {
38         {YACA_DIGEST_MD5,    EVP_md5},
39         {YACA_DIGEST_SHA1,   EVP_sha1},
40         {YACA_DIGEST_SHA224, EVP_sha224},
41         {YACA_DIGEST_SHA256, EVP_sha256},
42         {YACA_DIGEST_SHA384, EVP_sha384},
43         {YACA_DIGEST_SHA512, EVP_sha512},
44 };
45
46 static const size_t MESSAGE_DIGESTS_SIZE = sizeof(MESSAGE_DIGESTS) / sizeof(MESSAGE_DIGESTS[0]);
47
48 struct yaca_digest_context_s {
49         struct yaca_context_s ctx;
50
51         EVP_MD_CTX *md_ctx;
52         enum context_state_e state;
53 };
54
55 static bool CTX_DEFAULT_STATES[CTX_COUNT][CTX_COUNT] = {
56 /* from \ to  INIT, MSG, FIN */
57 /* INIT */  { 0,    1,    1 },
58 /* MSG  */  { 0,    1,    1 },
59 /* FIN  */  { 0,    0,    0 },
60 };
61
62 static bool verify_state_change(struct yaca_digest_context_s *c, enum context_state_e to)
63 {
64         int from = c->state;
65
66         return CTX_DEFAULT_STATES[from][to];
67 }
68
69 static struct yaca_digest_context_s *get_digest_context(const yaca_context_h ctx)
70 {
71         if (ctx == YACA_CONTEXT_NULL)
72                 return NULL;
73
74         switch (ctx->type) {
75         case YACA_CONTEXT_DIGEST:
76                 return (struct yaca_digest_context_s *)ctx;
77         default:
78                 return NULL;
79         }
80 }
81
82 static int get_digest_output_length(const yaca_context_h ctx,
83                                                                         size_t input_len,
84                                                                         size_t *output_len)
85 {
86         assert(output_len != NULL);
87
88         struct yaca_digest_context_s *c = get_digest_context(ctx);
89
90         if (c == NULL || input_len != 0)
91                 return YACA_ERROR_INVALID_PARAMETER;
92
93         int md_size = EVP_MD_CTX_size(c->md_ctx);
94         if (md_size <= 0)
95                 return YACA_ERROR_INTERNAL;
96
97         *output_len = md_size;
98
99         return YACA_ERROR_NONE;
100 }
101
102 static void destroy_digest_context(yaca_context_h ctx)
103 {
104         struct yaca_digest_context_s *c = get_digest_context(ctx);
105
106         if (c == NULL)
107                 return;
108
109         EVP_MD_CTX_destroy(c->md_ctx);
110         c->md_ctx = NULL;
111 }
112
113 int digest_get_algorithm(yaca_digest_algorithm_e algo, const EVP_MD **md)
114 {
115         int ret;
116         size_t i;
117
118         assert(md != NULL);
119
120         *md = NULL;
121         ret = YACA_ERROR_INVALID_PARAMETER;
122
123         for (i = 0; i < MESSAGE_DIGESTS_SIZE; ++i)
124                 if (MESSAGE_DIGESTS[i].algo == algo) {
125                         *md = MESSAGE_DIGESTS[i].digest();
126                         ret = YACA_ERROR_NONE;
127                         break;
128                 }
129
130         if (ret == YACA_ERROR_NONE && *md == NULL) {
131                 ret = YACA_ERROR_INTERNAL;
132                 ERROR_DUMP(ret);
133         }
134
135         return ret;
136 }
137
138 API int yaca_digest_initialize(yaca_context_h *ctx, yaca_digest_algorithm_e algo)
139 {
140         int ret;
141         struct yaca_digest_context_s *nc = NULL;
142         const EVP_MD *md;
143
144         if (ctx == NULL)
145                 return YACA_ERROR_INVALID_PARAMETER;
146
147         ret = yaca_zalloc(sizeof(struct yaca_digest_context_s), (void**)&nc);
148         if (ret != YACA_ERROR_NONE)
149                 return ret;
150
151         nc->ctx.type = YACA_CONTEXT_DIGEST;
152         nc->ctx.context_destroy = destroy_digest_context;
153         nc->ctx.get_output_length = get_digest_output_length;
154         nc->ctx.set_property = NULL;
155         nc->ctx.get_property = NULL;
156
157         ret = digest_get_algorithm(algo, &md);
158         if (ret != YACA_ERROR_NONE)
159                 goto exit;
160
161         nc->md_ctx = EVP_MD_CTX_create();
162         if (nc->md_ctx == NULL) {
163                 ret = YACA_ERROR_INTERNAL;
164                 ERROR_DUMP(ret);
165                 goto exit;
166         }
167
168         ret = EVP_DigestInit(nc->md_ctx, md);
169         if (ret != 1) {
170                 ret = YACA_ERROR_INTERNAL;
171                 ERROR_DUMP(ret);
172                 goto exit;
173         }
174
175         nc->state = CTX_INITIALIZED;
176         *ctx = (yaca_context_h)nc;
177         nc = NULL;
178         ret = YACA_ERROR_NONE;
179
180 exit:
181         yaca_context_destroy((yaca_context_h)nc);
182
183         return ret;
184 }
185
186 API int yaca_digest_update(yaca_context_h ctx, const char *message, size_t message_len)
187 {
188         struct yaca_digest_context_s *c = get_digest_context(ctx);
189         int ret;
190
191         if (c == NULL || message == NULL || message_len == 0)
192                 return YACA_ERROR_INVALID_PARAMETER;
193
194         if (!verify_state_change(c, CTX_MSG_UPDATED))
195                 return YACA_ERROR_INVALID_PARAMETER;
196
197         ret = EVP_DigestUpdate(c->md_ctx, message, message_len);
198         if (ret != 1) {
199                 ret = YACA_ERROR_INTERNAL;
200                 ERROR_DUMP(ret);
201                 return ret;
202         }
203
204         c->state = CTX_MSG_UPDATED;
205         return YACA_ERROR_NONE;
206 }
207
208 API int yaca_digest_finalize(yaca_context_h ctx, char *digest, size_t *digest_len)
209 {
210         struct yaca_digest_context_s *c = get_digest_context(ctx);
211         int ret;
212         unsigned len = 0;
213
214         if (c == NULL || digest == NULL || digest_len == NULL)
215                 return YACA_ERROR_INVALID_PARAMETER;
216
217         if (!verify_state_change(c, CTX_FINALIZED))
218                 return YACA_ERROR_INVALID_PARAMETER;
219
220         ret = EVP_DigestFinal_ex(c->md_ctx, (unsigned char*)digest, &len);
221         if (ret != 1) {
222                 ret = YACA_ERROR_INTERNAL;
223                 ERROR_DUMP(ret);
224                 return ret;
225         }
226
227         c->state = CTX_FINALIZED;
228         *digest_len = len;
229
230         return YACA_ERROR_NONE;
231 }