/src/hpn-ssh/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 | | { SSH_DIGEST_NULL, "NONEMAC", 0, EVP_md_null}, |
65 | | { -1, NULL, 0, NULL }, |
66 | | }; |
67 | | |
68 | | static const struct ssh_digest * |
69 | | ssh_digest_by_alg(int alg) |
70 | 140 | { |
71 | 140 | if (alg < 0 || alg >= SSH_DIGEST_MAX) |
72 | 0 | return NULL; |
73 | 140 | if (digests[alg].id != alg) /* sanity */ |
74 | 0 | return NULL; |
75 | 140 | if (digests[alg].mdfunc == NULL) |
76 | 0 | return NULL; |
77 | 140 | return &(digests[alg]); |
78 | 140 | } |
79 | | |
80 | | int |
81 | | ssh_digest_alg_by_name(const char *name) |
82 | 0 | { |
83 | 0 | int alg; |
84 | |
|
85 | 0 | for (alg = 0; digests[alg].id != -1; alg++) { |
86 | 0 | if (strcasecmp(name, digests[alg].name) == 0) |
87 | 0 | return digests[alg].id; |
88 | 0 | } |
89 | 0 | return -1; |
90 | 0 | } |
91 | | |
92 | | const char * |
93 | | ssh_digest_alg_name(int alg) |
94 | 0 | { |
95 | 0 | const struct ssh_digest *digest = ssh_digest_by_alg(alg); |
96 | |
|
97 | 0 | return digest == NULL ? NULL : digest->name; |
98 | 0 | } |
99 | | |
100 | | size_t |
101 | | ssh_digest_bytes(int alg) |
102 | 35 | { |
103 | 35 | const struct ssh_digest *digest = ssh_digest_by_alg(alg); |
104 | | |
105 | 35 | return digest == NULL ? 0 : digest->digest_len; |
106 | 35 | } |
107 | | |
108 | | size_t |
109 | | ssh_digest_blocksize(struct ssh_digest_ctx *ctx) |
110 | 35 | { |
111 | 35 | return EVP_MD_CTX_block_size(ctx->mdctx); |
112 | 35 | } |
113 | | |
114 | | struct ssh_digest_ctx * |
115 | | ssh_digest_start(int alg) |
116 | 105 | { |
117 | 105 | const struct ssh_digest *digest = ssh_digest_by_alg(alg); |
118 | 105 | struct ssh_digest_ctx *ret; |
119 | | |
120 | 105 | if (digest == NULL || ((ret = calloc(1, sizeof(*ret))) == NULL)) |
121 | 0 | return NULL; |
122 | 105 | ret->alg = alg; |
123 | 105 | if ((ret->mdctx = EVP_MD_CTX_new()) == NULL) { |
124 | 0 | free(ret); |
125 | 0 | return NULL; |
126 | 0 | } |
127 | 105 | if (EVP_DigestInit_ex(ret->mdctx, digest->mdfunc(), NULL) != 1) { |
128 | 0 | ssh_digest_free(ret); |
129 | 0 | return NULL; |
130 | 0 | } |
131 | 105 | return ret; |
132 | 105 | } |
133 | | |
134 | | int |
135 | | ssh_digest_copy_state(struct ssh_digest_ctx *from, struct ssh_digest_ctx *to) |
136 | 0 | { |
137 | 0 | if (from->alg != to->alg) |
138 | 0 | return SSH_ERR_INVALID_ARGUMENT; |
139 | | /* we have bcopy-style order while openssl has memcpy-style */ |
140 | 0 | if (!EVP_MD_CTX_copy_ex(to->mdctx, from->mdctx)) |
141 | 0 | return SSH_ERR_LIBCRYPTO_ERROR; |
142 | 0 | return 0; |
143 | 0 | } |
144 | | |
145 | | int |
146 | | ssh_digest_update(struct ssh_digest_ctx *ctx, const void *m, size_t mlen) |
147 | 0 | { |
148 | 0 | if (EVP_DigestUpdate(ctx->mdctx, m, mlen) != 1) |
149 | 0 | return SSH_ERR_LIBCRYPTO_ERROR; |
150 | 0 | return 0; |
151 | 0 | } |
152 | | |
153 | | int |
154 | | ssh_digest_update_buffer(struct ssh_digest_ctx *ctx, const struct sshbuf *b) |
155 | 0 | { |
156 | 0 | return ssh_digest_update(ctx, sshbuf_ptr(b), sshbuf_len(b)); |
157 | 0 | } |
158 | | |
159 | | int |
160 | | ssh_digest_final(struct ssh_digest_ctx *ctx, u_char *d, size_t dlen) |
161 | 0 | { |
162 | 0 | const struct ssh_digest *digest = ssh_digest_by_alg(ctx->alg); |
163 | 0 | u_int l = dlen; |
164 | |
|
165 | 0 | if (digest == NULL || dlen > UINT_MAX) |
166 | 0 | return SSH_ERR_INVALID_ARGUMENT; |
167 | 0 | if (dlen < digest->digest_len) /* No truncation allowed */ |
168 | 0 | return SSH_ERR_INVALID_ARGUMENT; |
169 | 0 | if (EVP_DigestFinal_ex(ctx->mdctx, d, &l) != 1) |
170 | 0 | return SSH_ERR_LIBCRYPTO_ERROR; |
171 | 0 | if (l != digest->digest_len) /* sanity */ |
172 | 0 | return SSH_ERR_INTERNAL_ERROR; |
173 | 0 | return 0; |
174 | 0 | } |
175 | | |
176 | | void |
177 | | ssh_digest_free(struct ssh_digest_ctx *ctx) |
178 | 105 | { |
179 | 105 | if (ctx == NULL) |
180 | 0 | return; |
181 | 105 | EVP_MD_CTX_free(ctx->mdctx); |
182 | 105 | freezero(ctx, sizeof(*ctx)); |
183 | 105 | } |
184 | | |
185 | | int |
186 | | ssh_digest_memory(int alg, const void *m, size_t mlen, u_char *d, size_t dlen) |
187 | 0 | { |
188 | 0 | const struct ssh_digest *digest = ssh_digest_by_alg(alg); |
189 | 0 | u_int mdlen; |
190 | |
|
191 | 0 | if (digest == NULL) |
192 | 0 | return SSH_ERR_INVALID_ARGUMENT; |
193 | 0 | if (dlen > UINT_MAX) |
194 | 0 | return SSH_ERR_INVALID_ARGUMENT; |
195 | 0 | if (dlen < digest->digest_len) |
196 | 0 | return SSH_ERR_INVALID_ARGUMENT; |
197 | 0 | mdlen = dlen; |
198 | 0 | if (!EVP_Digest(m, mlen, d, &mdlen, digest->mdfunc(), NULL)) |
199 | 0 | return SSH_ERR_LIBCRYPTO_ERROR; |
200 | 0 | return 0; |
201 | 0 | } |
202 | | |
203 | | int |
204 | | ssh_digest_buffer(int alg, const struct sshbuf *b, u_char *d, size_t dlen) |
205 | 0 | { |
206 | 0 | return ssh_digest_memory(alg, sshbuf_ptr(b), sshbuf_len(b), d, dlen); |
207 | 0 | } |
208 | | #endif /* WITH_OPENSSL */ |