Remove CMAC from digest algorithms.
[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 #include <assert.h>
20 #include <stdint.h>
21
22 #include <openssl/evp.h>
23 #include <openssl/err.h>
24
25 #include <yaca/crypto.h>
26 #include <yaca/error.h>
27 #include <yaca/types.h>
28
29 #include "internal.h"
30
31 struct yaca_digest_ctx_s
32 {
33         struct yaca_ctx_s ctx;
34
35         EVP_MD_CTX *mdctx;
36 };
37
38 static struct yaca_digest_ctx_s *get_digest_ctx(const yaca_ctx_h ctx)
39 {
40         if (ctx == YACA_CTX_NULL)
41                 return NULL;
42
43         switch (ctx->type)
44         {
45         case YACA_CTX_DIGEST:
46                 return (struct yaca_digest_ctx_s *)ctx;
47         default:
48                 return NULL;
49         }
50 }
51
52 static int get_digest_output_length(const yaca_ctx_h ctx, size_t input_len, size_t *output_len)
53 {
54         struct yaca_digest_ctx_s *c = get_digest_ctx(ctx);
55
56         if (c == NULL)
57                 return YACA_ERROR_INVALID_ARGUMENT;
58
59         *output_len = EVP_MD_CTX_size(c->mdctx);
60         return 0;
61 }
62
63 static void destroy_digest_context(yaca_ctx_h ctx)
64 {
65         struct yaca_digest_ctx_s *c = get_digest_ctx(ctx);
66
67         if (c == NULL)
68                 return;
69
70         EVP_MD_CTX_destroy(c->mdctx);
71         c->mdctx = NULL;
72 }
73
74 int digest_get_algorithm(yaca_digest_algo_e algo, const EVP_MD **md)
75 {
76         int ret = 0;
77
78         if (!md)
79                 return YACA_ERROR_INVALID_ARGUMENT;
80
81         *md = NULL;
82
83         switch (algo)
84         {
85         case YACA_DIGEST_MD5:
86                 *md = EVP_md5();
87                 break;
88         case YACA_DIGEST_SHA1:
89                 *md = EVP_sha1();
90                 break;
91         case YACA_DIGEST_SHA224:
92                 *md = EVP_sha224();
93                 break;
94         case YACA_DIGEST_SHA256:
95                 *md = EVP_sha256();
96                 break;
97         case YACA_DIGEST_SHA384:
98                 *md = EVP_sha384();
99                 break;
100         case YACA_DIGEST_SHA512:
101                 *md = EVP_sha512();
102                 break;
103         default:
104                 ret = YACA_ERROR_INVALID_ARGUMENT;
105                 break;
106         }
107
108         if (ret == 0 && *md == NULL) {
109                 ret = YACA_ERROR_INTERNAL;
110                 ERROR_DUMP(ret);
111         }
112
113         return ret;
114 }
115
116 API int yaca_digest_init(yaca_ctx_h *ctx, yaca_digest_algo_e algo)
117 {
118         int ret;
119         struct yaca_digest_ctx_s *nc = NULL;
120         const EVP_MD *md;
121
122         if (ctx == NULL)
123                 return YACA_ERROR_INVALID_ARGUMENT;
124
125         nc = yaca_zalloc(sizeof(struct yaca_digest_ctx_s));
126         if (nc == NULL)
127                 return YACA_ERROR_OUT_OF_MEMORY;
128
129         nc->ctx.type = YACA_CTX_DIGEST;
130         nc->ctx.ctx_destroy = destroy_digest_context;
131         nc->ctx.get_output_length = get_digest_output_length;
132
133         ret = digest_get_algorithm(algo, &md);
134         if (ret < 0)
135                 goto free;
136
137         nc->mdctx = EVP_MD_CTX_create();
138         if (nc->mdctx == NULL) {
139                 ret = YACA_ERROR_INTERNAL;
140                 ERROR_DUMP(ret);
141                 goto free;
142         }
143
144         ret = EVP_DigestInit(nc->mdctx, md);
145         if (ret != 1) {
146                 ret = YACA_ERROR_INTERNAL;
147                 ERROR_DUMP(ret);
148                 goto ctx;
149         }
150
151         *ctx = (yaca_ctx_h)nc;
152
153         return 0;
154
155 ctx:
156         EVP_MD_CTX_destroy(nc->mdctx);
157 free:
158         yaca_free(nc);
159         return ret;
160 }
161
162 API int yaca_digest_update(yaca_ctx_h ctx, const char *data, size_t data_len)
163 {
164         struct yaca_digest_ctx_s *c = get_digest_ctx(ctx);
165         int ret;
166
167         if (c == NULL || data == NULL || data_len == 0)
168                 return YACA_ERROR_INVALID_ARGUMENT;
169
170         ret = EVP_DigestUpdate(c->mdctx, data, data_len);
171         if (ret != 1) {
172                 ret = YACA_ERROR_INTERNAL;
173                 ERROR_DUMP(ret);
174                 return ret;
175         }
176
177         return 0;
178 }
179
180 API int yaca_digest_final(yaca_ctx_h ctx, char *digest, size_t *digest_len)
181 {
182         struct yaca_digest_ctx_s *c = get_digest_ctx(ctx);
183         int ret;
184         unsigned len = 0;
185
186         if (c == NULL || digest == NULL || digest_len == NULL)
187                 return YACA_ERROR_INVALID_ARGUMENT;
188
189         if (*digest_len == 0 || *digest_len > UINT_MAX) // DigestFinal accepts uint
190                 return YACA_ERROR_INVALID_ARGUMENT;
191
192         ret = EVP_DigestFinal_ex(c->mdctx, (unsigned char*)digest, &len);
193         if (ret != 1) {
194                 ret = YACA_ERROR_INTERNAL;
195                 ERROR_DUMP(ret);
196                 return ret;
197         }
198
199         *digest_len = len;
200
201         return 0;
202 }