d51dcaa971842e47a62defcdfc7dae31e8da91c1
[tinc] / src / openssl / digest.c
1 /*
2     digest.c -- Digest handling
3     Copyright (C) 2007-2016 Guus Sliepen <guus@tinc-vpn.org>
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License along
16     with this program; if not, write to the Free Software Foundation, Inc.,
17     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "../system.h"
21 #include "../utils.h"
22 #include "../xalloc.h"
23
24 #include <openssl/err.h>
25 #include <openssl/hmac.h>
26
27 #include "digest.h"
28 #include "../digest.h"
29 #include "../logger.h"
30
31 static digest_t *digest_open(const EVP_MD *evp_md, int maclength) {
32         digest_t *digest = xzalloc(sizeof(*digest));
33         digest->digest = evp_md;
34
35         int digestlen = EVP_MD_size(digest->digest);
36
37         if(maclength > digestlen || maclength < 0) {
38                 digest->maclength = digestlen;
39         } else {
40                 digest->maclength = maclength;
41         }
42
43         return digest;
44 }
45
46 digest_t *digest_open_by_name(const char *name, int maclength) {
47         const EVP_MD *evp_md = EVP_get_digestbyname(name);
48
49         if(!evp_md) {
50                 logger(DEBUG_ALWAYS, LOG_DEBUG, "Unknown digest name '%s'!", name);
51                 return false;
52         }
53
54         return digest_open(evp_md, maclength);
55 }
56
57 digest_t *digest_open_by_nid(int nid, int maclength) {
58         const EVP_MD *evp_md = EVP_get_digestbynid(nid);
59
60         if(!evp_md) {
61                 logger(DEBUG_ALWAYS, LOG_DEBUG, "Unknown digest nid %d!", nid);
62                 return false;
63         }
64
65         return digest_open(evp_md, maclength);
66 }
67
68 bool digest_set_key(digest_t *digest, const void *key, size_t len) {
69         digest->hmac_ctx = HMAC_CTX_new();
70         HMAC_Init_ex(digest->hmac_ctx, key, len, digest->digest, NULL);
71
72         if(!digest->hmac_ctx) {
73                 abort();
74         }
75
76         return true;
77 }
78
79 void digest_close(digest_t *digest) {
80         if(!digest) {
81                 return;
82         }
83
84         if(digest->md_ctx) {
85                 EVP_MD_CTX_destroy(digest->md_ctx);
86         }
87
88         if(digest->hmac_ctx) {
89                 HMAC_CTX_free(digest->hmac_ctx);
90         }
91
92         free(digest);
93 }
94
95 bool digest_create(digest_t *digest, const void *indata, size_t inlen, void *outdata) {
96         size_t len = EVP_MD_size(digest->digest);
97         unsigned char tmpdata[len];
98
99         if(digest->hmac_ctx) {
100                 if(!HMAC_Init_ex(digest->hmac_ctx, NULL, 0, NULL, NULL)
101                                 || !HMAC_Update(digest->hmac_ctx, indata, inlen)
102                                 || !HMAC_Final(digest->hmac_ctx, tmpdata, NULL)) {
103                         logger(DEBUG_ALWAYS, LOG_DEBUG, "Error creating digest: %s", ERR_error_string(ERR_get_error(), NULL));
104                         return false;
105                 }
106         } else {
107                 if(!digest->md_ctx) {
108                         digest->md_ctx = EVP_MD_CTX_create();
109                 }
110
111                 if(!digest->md_ctx) {
112                         abort();
113                 }
114
115                 if(!EVP_DigestInit(digest->md_ctx, digest->digest)
116                                 || !EVP_DigestUpdate(digest->md_ctx, indata, inlen)
117                                 || !EVP_DigestFinal(digest->md_ctx, tmpdata, NULL)) {
118                         logger(DEBUG_ALWAYS, LOG_DEBUG, "Error creating digest: %s", ERR_error_string(ERR_get_error(), NULL));
119                         return false;
120                 }
121         }
122
123         memcpy(outdata, tmpdata, digest->maclength);
124         return true;
125 }
126
127 bool digest_verify(digest_t *digest, const void *indata, size_t inlen, const void *cmpdata) {
128         size_t len = digest->maclength;
129         unsigned char outdata[len];
130
131         return digest_create(digest, indata, inlen, outdata) && !memcmp(cmpdata, outdata, digest->maclength);
132 }
133
134 int digest_get_nid(const digest_t *digest) {
135         if(!digest || !digest->digest) {
136                 return 0;
137         }
138
139         return EVP_MD_type(digest->digest);
140 }
141
142 size_t digest_keylength(const digest_t *digest) {
143         if(!digest || !digest->digest) {
144                 return 0;
145         }
146
147         return EVP_MD_size(digest->digest);
148 }
149
150 size_t digest_length(const digest_t *digest) {
151         if(!digest) {
152                 return 0;
153         }
154
155         return digest->maclength;
156 }
157
158 bool digest_active(const digest_t *digest) {
159         return digest && digest->digest && EVP_MD_type(digest->digest) != 0;
160 }