/src/openssh/digest-openssl.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* $OpenBSD: digest-openssl.c,v 1.9 2020/10/29 02:52:43 djm Exp $ */ |
2 | | /* |
3 | | * Copyright (c) 2013 Damien Miller <djm@mindrot.org> |
4 | | * |
5 | | * Permission to use, copy, modify, and distribute this software for any |
6 | | * purpose with or without fee is hereby granted, provided that the above |
7 | | * copyright notice and this permission notice appear in all copies. |
8 | | * |
9 | | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
10 | | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
11 | | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
12 | | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
13 | | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
14 | | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
15 | | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
16 | | */ |
17 | | |
18 | | #include "includes.h" |
19 | | |
20 | | #ifdef WITH_OPENSSL |
21 | | |
22 | | #include <sys/types.h> |
23 | | #include <limits.h> |
24 | | #include <stdlib.h> |
25 | | #include <string.h> |
26 | | |
27 | | #include <openssl/evp.h> |
28 | | |
29 | | #include "openbsd-compat/openssl-compat.h" |
30 | | |
31 | | #include "sshbuf.h" |
32 | | #include "digest.h" |
33 | | #include "ssherr.h" |
34 | | |
35 | | #ifndef HAVE_EVP_SHA256 |
36 | | # define EVP_sha256 NULL |
37 | | #endif |
38 | | #ifndef HAVE_EVP_SHA384 |
39 | | # define EVP_sha384 NULL |
40 | | #endif |
41 | | #ifndef HAVE_EVP_SHA512 |
42 | | # define EVP_sha512 NULL |
43 | | #endif |
44 | | |
45 | | struct ssh_digest_ctx { |
46 | | int alg; |
47 | | EVP_MD_CTX *mdctx; |
48 | | }; |
49 | | |
50 | | struct ssh_digest { |
51 | | int id; |
52 | | const char *name; |
53 | | size_t digest_len; |
54 | | const EVP_MD *(*mdfunc)(void); |
55 | | }; |
56 | | |
57 | | /* NB. Indexed directly by algorithm number */ |
58 | | const struct ssh_digest digests[] = { |
59 | | { SSH_DIGEST_MD5, "MD5", 16, EVP_md5 }, |
60 | | { SSH_DIGEST_SHA1, "SHA1", 20, EVP_sha1 }, |
61 | | { SSH_DIGEST_SHA256, "SHA256", 32, EVP_sha256 }, |
62 | | { SSH_DIGEST_SHA384, "SHA384", 48, EVP_sha384 }, |
63 | | { SSH_DIGEST_SHA512, "SHA512", 64, EVP_sha512 }, |
64 | | { -1, NULL, 0, NULL }, |
65 | | }; |
66 | | |
67 | | static const struct ssh_digest * |
68 | | ssh_digest_by_alg(int alg) |
69 | 6.22k | { |
70 | 6.22k | if (alg < 0 || alg >= SSH_DIGEST_MAX) |
71 | 0 | return NULL; |
72 | 6.22k | if (digests[alg].id != alg) /* sanity */ |
73 | 0 | return NULL; |
74 | 6.22k | if (digests[alg].mdfunc == NULL) |
75 | 0 | return NULL; |
76 | 6.22k | return &(digests[alg]); |
77 | 6.22k | } |
78 | | |
79 | | int |
80 | | ssh_digest_alg_by_name(const char *name) |
81 | 2.06k | { |
82 | 2.06k | int alg; |
83 | | |
84 | 8.27k | for (alg = 0; digests[alg].id != -1; alg++) { |
85 | 8.27k | if (strcasecmp(name, digests[alg].name) == 0) |
86 | 2.06k | return digests[alg].id; |
87 | 8.27k | } |
88 | 0 | return -1; |
89 | 2.06k | } |
90 | | |
91 | | const char * |
92 | | ssh_digest_alg_name(int alg) |
93 | 0 | { |
94 | 0 | const struct ssh_digest *digest = ssh_digest_by_alg(alg); |
95 | |
|
96 | 0 | return digest == NULL ? NULL : digest->name; |
97 | 0 | } |
98 | | |
99 | | size_t |
100 | | ssh_digest_bytes(int alg) |
101 | 4.13k | { |
102 | 4.13k | const struct ssh_digest *digest = ssh_digest_by_alg(alg); |
103 | | |
104 | 4.13k | return digest == NULL ? 0 : digest->digest_len; |
105 | 4.13k | } |
106 | | |
107 | | size_t |
108 | | ssh_digest_blocksize(struct ssh_digest_ctx *ctx) |
109 | 0 | { |
110 | 0 | return EVP_MD_CTX_block_size(ctx->mdctx); |
111 | 0 | } |
112 | | |
113 | | struct ssh_digest_ctx * |
114 | | ssh_digest_start(int alg) |
115 | 0 | { |
116 | 0 | const struct ssh_digest *digest = ssh_digest_by_alg(alg); |
117 | 0 | struct ssh_digest_ctx *ret; |
118 | |
|
119 | 0 | if (digest == NULL || ((ret = calloc(1, sizeof(*ret))) == NULL)) |
120 | 0 | return NULL; |
121 | 0 | ret->alg = alg; |
122 | 0 | if ((ret->mdctx = EVP_MD_CTX_new()) == NULL) { |
123 | 0 | free(ret); |
124 | 0 | return NULL; |
125 | 0 | } |
126 | 0 | if (EVP_DigestInit_ex(ret->mdctx, digest->mdfunc(), NULL) != 1) { |
127 | 0 | ssh_digest_free(ret); |
128 | 0 | return NULL; |
129 | 0 | } |
130 | 0 | return ret; |
131 | 0 | } |
132 | | |
133 | | int |
134 | | ssh_digest_copy_state(struct ssh_digest_ctx *from, struct ssh_digest_ctx *to) |
135 | 0 | { |
136 | 0 | if (from->alg != to->alg) |
137 | 0 | return SSH_ERR_INVALID_ARGUMENT; |
138 | | /* we have bcopy-style order while openssl has memcpy-style */ |
139 | 0 | if (!EVP_MD_CTX_copy_ex(to->mdctx, from->mdctx)) |
140 | 0 | return SSH_ERR_LIBCRYPTO_ERROR; |
141 | 0 | return 0; |
142 | 0 | } |
143 | | |
144 | | int |
145 | | ssh_digest_update(struct ssh_digest_ctx *ctx, const void *m, size_t mlen) |
146 | 0 | { |
147 | 0 | if (EVP_DigestUpdate(ctx->mdctx, m, mlen) != 1) |
148 | 0 | return SSH_ERR_LIBCRYPTO_ERROR; |
149 | 0 | return 0; |
150 | 0 | } |
151 | | |
152 | | int |
153 | | ssh_digest_update_buffer(struct ssh_digest_ctx *ctx, const struct sshbuf *b) |
154 | 0 | { |
155 | 0 | return ssh_digest_update(ctx, sshbuf_ptr(b), sshbuf_len(b)); |
156 | 0 | } |
157 | | |
158 | | int |
159 | | ssh_digest_final(struct ssh_digest_ctx *ctx, u_char *d, size_t dlen) |
160 | 0 | { |
161 | 0 | const struct ssh_digest *digest = ssh_digest_by_alg(ctx->alg); |
162 | 0 | u_int l = dlen; |
163 | |
|
164 | 0 | if (digest == NULL || dlen > UINT_MAX) |
165 | 0 | return SSH_ERR_INVALID_ARGUMENT; |
166 | 0 | if (dlen < digest->digest_len) /* No truncation allowed */ |
167 | 0 | return SSH_ERR_INVALID_ARGUMENT; |
168 | 0 | if (EVP_DigestFinal_ex(ctx->mdctx, d, &l) != 1) |
169 | 0 | return SSH_ERR_LIBCRYPTO_ERROR; |
170 | 0 | if (l != digest->digest_len) /* sanity */ |
171 | 0 | return SSH_ERR_INTERNAL_ERROR; |
172 | 0 | return 0; |
173 | 0 | } |
174 | | |
175 | | void |
176 | | ssh_digest_free(struct ssh_digest_ctx *ctx) |
177 | 0 | { |
178 | 0 | if (ctx == NULL) |
179 | 0 | return; |
180 | 0 | EVP_MD_CTX_free(ctx->mdctx); |
181 | 0 | freezero(ctx, sizeof(*ctx)); |
182 | 0 | } |
183 | | |
184 | | int |
185 | | ssh_digest_memory(int alg, const void *m, size_t mlen, u_char *d, size_t dlen) |
186 | 2.09k | { |
187 | 2.09k | const struct ssh_digest *digest = ssh_digest_by_alg(alg); |
188 | 2.09k | u_int mdlen; |
189 | | |
190 | 2.09k | if (digest == NULL) |
191 | 0 | return SSH_ERR_INVALID_ARGUMENT; |
192 | 2.09k | if (dlen > UINT_MAX) |
193 | 0 | return SSH_ERR_INVALID_ARGUMENT; |
194 | 2.09k | if (dlen < digest->digest_len) |
195 | 0 | return SSH_ERR_INVALID_ARGUMENT; |
196 | 2.09k | mdlen = dlen; |
197 | 2.09k | if (!EVP_Digest(m, mlen, d, &mdlen, digest->mdfunc(), NULL)) |
198 | 0 | return SSH_ERR_LIBCRYPTO_ERROR; |
199 | 2.09k | return 0; |
200 | 2.09k | } |
201 | | |
202 | | int |
203 | | ssh_digest_buffer(int alg, const struct sshbuf *b, u_char *d, size_t dlen) |
204 | 2.06k | { |
205 | 2.06k | return ssh_digest_memory(alg, sshbuf_ptr(b), sshbuf_len(b), d, dlen); |
206 | 2.06k | } |
207 | | #endif /* WITH_OPENSSL */ |