Coverage Report

Created: 2025-07-01 07:00

/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 */