]>
Commit | Line | Data |
---|---|---|
d5ba1c03 | 1 | /* $OpenBSD: digest-libc.c,v 1.7 2020/02/26 13:40:09 jsg Exp $ */ |
b3051d01 DM |
2 | /* |
3 | * Copyright (c) 2013 Damien Miller <djm@mindrot.org> | |
ec93d151 | 4 | * Copyright (c) 2014 Markus Friedl. All rights reserved. |
b3051d01 DM |
5 | * |
6 | * Permission to use, copy, modify, and distribute this software for any | |
7 | * purpose with or without fee is hereby granted, provided that the above | |
8 | * copyright notice and this permission notice appear in all copies. | |
9 | * | |
10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
17 | */ | |
18 | ||
19 | #include "includes.h" | |
20 | ||
72ef7c14 DM |
21 | #ifndef WITH_OPENSSL |
22 | ||
b3051d01 DM |
23 | #include <sys/types.h> |
24 | #include <limits.h> | |
25 | #include <stdlib.h> | |
26 | #include <string.h> | |
27 | ||
72ef7c14 | 28 | #if 0 |
ec93d151 DM |
29 | #include <md5.h> |
30 | #include <rmd160.h> | |
11cba2a4 DT |
31 | #endif |
32 | #ifdef HAVE_SHA1_H | |
ec93d151 | 33 | #include <sha1.h> |
11cba2a4 DT |
34 | #endif |
35 | #ifdef HAVE_SHA2_H | |
ec93d151 | 36 | #include <sha2.h> |
72ef7c14 | 37 | #endif |
d23a91ff | 38 | |
1c9853a6 DT |
39 | #if !defined(SHA256_BLOCK_LENGTH) && defined(SHA256_HMAC_BLOCK_SIZE) |
40 | #define SHA256_BLOCK_LENGTH SHA256_HMAC_BLOCK_SIZE | |
41 | #endif | |
42 | #if !defined(SHA384_BLOCK_LENGTH) && defined(SHA512_HMAC_BLOCK_SIZE) | |
43 | #define SHA384_BLOCK_LENGTH SHA512_HMAC_BLOCK_SIZE | |
44 | #endif | |
45 | #if !defined(SHA512_BLOCK_LENGTH) && defined(SHA512_HMAC_BLOCK_SIZE) | |
46 | #define SHA512_BLOCK_LENGTH SHA512_HMAC_BLOCK_SIZE | |
47 | #endif | |
48 | ||
8668706d DM |
49 | #include "ssherr.h" |
50 | #include "sshbuf.h" | |
b3051d01 DM |
51 | #include "digest.h" |
52 | ||
ec93d151 DM |
53 | typedef void md_init_fn(void *mdctx); |
54 | typedef void md_update_fn(void *mdctx, const u_int8_t *m, size_t mlen); | |
55 | typedef void md_final_fn(u_int8_t[], void *mdctx); | |
56 | ||
b3051d01 DM |
57 | struct ssh_digest_ctx { |
58 | int alg; | |
ec93d151 | 59 | void *mdctx; |
b3051d01 DM |
60 | }; |
61 | ||
62 | struct ssh_digest { | |
63 | int id; | |
64 | const char *name; | |
ec93d151 | 65 | size_t block_len; |
b3051d01 | 66 | size_t digest_len; |
ec93d151 DM |
67 | size_t ctx_len; |
68 | md_init_fn *md_init; | |
69 | md_update_fn *md_update; | |
70 | md_final_fn *md_final; | |
b3051d01 DM |
71 | }; |
72 | ||
73 | /* NB. Indexed directly by algorithm number */ | |
ec93d151 DM |
74 | const struct ssh_digest digests[SSH_DIGEST_MAX] = { |
75 | { | |
76 | SSH_DIGEST_MD5, | |
77 | "MD5", | |
78 | MD5_BLOCK_LENGTH, | |
79 | MD5_DIGEST_LENGTH, | |
80 | sizeof(MD5_CTX), | |
81 | (md_init_fn *) MD5Init, | |
82 | (md_update_fn *) MD5Update, | |
83 | (md_final_fn *) MD5Final | |
84 | }, | |
ec93d151 DM |
85 | { |
86 | SSH_DIGEST_SHA1, | |
87 | "SHA1", | |
88 | SHA1_BLOCK_LENGTH, | |
89 | SHA1_DIGEST_LENGTH, | |
90 | sizeof(SHA1_CTX), | |
91 | (md_init_fn *) SHA1Init, | |
92 | (md_update_fn *) SHA1Update, | |
93 | (md_final_fn *) SHA1Final | |
94 | }, | |
95 | { | |
96 | SSH_DIGEST_SHA256, | |
97 | "SHA256", | |
98 | SHA256_BLOCK_LENGTH, | |
99 | SHA256_DIGEST_LENGTH, | |
11cba2a4 DT |
100 | sizeof(SHA2_CTX), |
101 | (md_init_fn *) SHA256Init, | |
102 | (md_update_fn *) SHA256Update, | |
103 | (md_final_fn *) SHA256Final | |
ec93d151 DM |
104 | }, |
105 | { | |
106 | SSH_DIGEST_SHA384, | |
107 | "SHA384", | |
108 | SHA384_BLOCK_LENGTH, | |
109 | SHA384_DIGEST_LENGTH, | |
11cba2a4 DT |
110 | sizeof(SHA2_CTX), |
111 | (md_init_fn *) SHA384Init, | |
112 | (md_update_fn *) SHA384Update, | |
113 | (md_final_fn *) SHA384Final | |
ec93d151 DM |
114 | }, |
115 | { | |
116 | SSH_DIGEST_SHA512, | |
117 | "SHA512", | |
118 | SHA512_BLOCK_LENGTH, | |
119 | SHA512_DIGEST_LENGTH, | |
11cba2a4 DT |
120 | sizeof(SHA2_CTX), |
121 | (md_init_fn *) SHA512Init, | |
122 | (md_update_fn *) SHA512Update, | |
123 | (md_final_fn *) SHA512Final | |
ec93d151 | 124 | } |
b3051d01 DM |
125 | }; |
126 | ||
127 | static const struct ssh_digest * | |
128 | ssh_digest_by_alg(int alg) | |
129 | { | |
130 | if (alg < 0 || alg >= SSH_DIGEST_MAX) | |
131 | return NULL; | |
132 | if (digests[alg].id != alg) /* sanity */ | |
133 | return NULL; | |
134 | return &(digests[alg]); | |
135 | } | |
136 | ||
56d1c83c | 137 | int |
138 | ssh_digest_alg_by_name(const char *name) | |
139 | { | |
140 | int alg; | |
141 | ||
142 | for (alg = 0; alg < SSH_DIGEST_MAX; alg++) { | |
143 | if (strcasecmp(name, digests[alg].name) == 0) | |
144 | return digests[alg].id; | |
145 | } | |
146 | return -1; | |
147 | } | |
148 | ||
149 | const char * | |
150 | ssh_digest_alg_name(int alg) | |
151 | { | |
152 | const struct ssh_digest *digest = ssh_digest_by_alg(alg); | |
153 | ||
154 | return digest == NULL ? NULL : digest->name; | |
155 | } | |
156 | ||
b3051d01 DM |
157 | size_t |
158 | ssh_digest_bytes(int alg) | |
159 | { | |
160 | const struct ssh_digest *digest = ssh_digest_by_alg(alg); | |
161 | ||
162 | return digest == NULL ? 0 : digest->digest_len; | |
163 | } | |
164 | ||
4e8d937a DM |
165 | size_t |
166 | ssh_digest_blocksize(struct ssh_digest_ctx *ctx) | |
167 | { | |
ec93d151 DM |
168 | const struct ssh_digest *digest = ssh_digest_by_alg(ctx->alg); |
169 | ||
170 | return digest == NULL ? 0 : digest->block_len; | |
4e8d937a DM |
171 | } |
172 | ||
b3051d01 DM |
173 | struct ssh_digest_ctx * |
174 | ssh_digest_start(int alg) | |
175 | { | |
176 | const struct ssh_digest *digest = ssh_digest_by_alg(alg); | |
177 | struct ssh_digest_ctx *ret; | |
178 | ||
d5b1507a | 179 | if (digest == NULL || (ret = calloc(1, sizeof(*ret))) == NULL) |
b3051d01 | 180 | return NULL; |
ec93d151 | 181 | if ((ret->mdctx = calloc(1, digest->ctx_len)) == NULL) { |
b3051d01 DM |
182 | free(ret); |
183 | return NULL; | |
184 | } | |
ec93d151 DM |
185 | ret->alg = alg; |
186 | digest->md_init(ret->mdctx); | |
b3051d01 DM |
187 | return ret; |
188 | } | |
189 | ||
4e8d937a DM |
190 | int |
191 | ssh_digest_copy_state(struct ssh_digest_ctx *from, struct ssh_digest_ctx *to) | |
192 | { | |
ec93d151 DM |
193 | const struct ssh_digest *digest = ssh_digest_by_alg(from->alg); |
194 | ||
195 | if (digest == NULL || from->alg != to->alg) | |
8668706d | 196 | return SSH_ERR_INVALID_ARGUMENT; |
ec93d151 | 197 | memcpy(to->mdctx, from->mdctx, digest->ctx_len); |
4e8d937a DM |
198 | return 0; |
199 | } | |
200 | ||
b3051d01 DM |
201 | int |
202 | ssh_digest_update(struct ssh_digest_ctx *ctx, const void *m, size_t mlen) | |
203 | { | |
ec93d151 DM |
204 | const struct ssh_digest *digest = ssh_digest_by_alg(ctx->alg); |
205 | ||
206 | if (digest == NULL) | |
8668706d | 207 | return SSH_ERR_INVALID_ARGUMENT; |
ec93d151 | 208 | digest->md_update(ctx->mdctx, m, mlen); |
b3051d01 DM |
209 | return 0; |
210 | } | |
211 | ||
212 | int | |
8668706d | 213 | ssh_digest_update_buffer(struct ssh_digest_ctx *ctx, const struct sshbuf *b) |
b3051d01 | 214 | { |
8668706d | 215 | return ssh_digest_update(ctx, sshbuf_ptr(b), sshbuf_len(b)); |
b3051d01 DM |
216 | } |
217 | ||
218 | int | |
219 | ssh_digest_final(struct ssh_digest_ctx *ctx, u_char *d, size_t dlen) | |
220 | { | |
221 | const struct ssh_digest *digest = ssh_digest_by_alg(ctx->alg); | |
b3051d01 | 222 | |
ec93d151 | 223 | if (digest == NULL) |
8668706d | 224 | return SSH_ERR_INVALID_ARGUMENT; |
b3051d01 | 225 | if (dlen > UINT_MAX) |
8668706d | 226 | return SSH_ERR_INVALID_ARGUMENT; |
b3051d01 | 227 | if (dlen < digest->digest_len) /* No truncation allowed */ |
8668706d | 228 | return SSH_ERR_INVALID_ARGUMENT; |
ec93d151 | 229 | digest->md_final(d, ctx->mdctx); |
b3051d01 DM |
230 | return 0; |
231 | } | |
232 | ||
233 | void | |
234 | ssh_digest_free(struct ssh_digest_ctx *ctx) | |
235 | { | |
ec93d151 DM |
236 | const struct ssh_digest *digest; |
237 | ||
4e8d937a | 238 | if (ctx != NULL) { |
ec93d151 DM |
239 | digest = ssh_digest_by_alg(ctx->alg); |
240 | if (digest) { | |
db3c595e | 241 | explicit_bzero(ctx->mdctx, digest->ctx_len); |
ec93d151 | 242 | free(ctx->mdctx); |
d5ba1c03 | 243 | freezero(ctx, sizeof(*ctx)); |
ec93d151 | 244 | } |
4e8d937a | 245 | } |
b3051d01 DM |
246 | } |
247 | ||
248 | int | |
249 | ssh_digest_memory(int alg, const void *m, size_t mlen, u_char *d, size_t dlen) | |
250 | { | |
251 | struct ssh_digest_ctx *ctx = ssh_digest_start(alg); | |
252 | ||
253 | if (ctx == NULL) | |
8668706d | 254 | return SSH_ERR_INVALID_ARGUMENT; |
b3051d01 DM |
255 | if (ssh_digest_update(ctx, m, mlen) != 0 || |
256 | ssh_digest_final(ctx, d, dlen) != 0) | |
8668706d | 257 | return SSH_ERR_INVALID_ARGUMENT; |
b3051d01 DM |
258 | ssh_digest_free(ctx); |
259 | return 0; | |
260 | } | |
261 | ||
262 | int | |
8668706d | 263 | ssh_digest_buffer(int alg, const struct sshbuf *b, u_char *d, size_t dlen) |
b3051d01 | 264 | { |
8668706d | 265 | return ssh_digest_memory(alg, sshbuf_ptr(b), sshbuf_len(b), d, dlen); |
b3051d01 | 266 | } |
72ef7c14 | 267 | #endif /* !WITH_OPENSSL */ |