Coverage Report

Created: 2024-07-27 06:06

/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
6.92k
{
71
6.92k
  if (alg < 0 || alg >= SSH_DIGEST_MAX)
72
0
    return NULL;
73
6.92k
  if (digests[alg].id != alg) /* sanity */
74
0
    return NULL;
75
6.92k
  if (digests[alg].mdfunc == NULL)
76
0
    return NULL;
77
6.92k
  return &(digests[alg]);
78
6.92k
}
79
80
int
81
ssh_digest_alg_by_name(const char *name)
82
2.24k
{
83
2.24k
  int alg;
84
85
9.12k
  for (alg = 0; digests[alg].id != -1; alg++) {
86
9.12k
    if (strcasecmp(name, digests[alg].name) == 0)
87
2.24k
      return digests[alg].id;
88
9.12k
  }
89
0
  return -1;
90
2.24k
}
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
4.63k
{
103
4.63k
  const struct ssh_digest *digest = ssh_digest_by_alg(alg);
104
105
4.63k
  return digest == NULL ? 0 : digest->digest_len;
106
4.63k
}
107
108
size_t
109
ssh_digest_blocksize(struct ssh_digest_ctx *ctx)
110
0
{
111
0
  return EVP_MD_CTX_block_size(ctx->mdctx);
112
0
}
113
114
struct ssh_digest_ctx *
115
ssh_digest_start(int alg)
116
0
{
117
0
  const struct ssh_digest *digest = ssh_digest_by_alg(alg);
118
0
  struct ssh_digest_ctx *ret;
119
120
0
  if (digest == NULL || ((ret = calloc(1, sizeof(*ret))) == NULL))
121
0
    return NULL;
122
0
  ret->alg = alg;
123
0
  if ((ret->mdctx = EVP_MD_CTX_new()) == NULL) {
124
0
    free(ret);
125
0
    return NULL;
126
0
  }
127
0
  if (EVP_DigestInit_ex(ret->mdctx, digest->mdfunc(), NULL) != 1) {
128
0
    ssh_digest_free(ret);
129
0
    return NULL;
130
0
  }
131
0
  return ret;
132
0
}
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
0
{
179
0
  if (ctx == NULL)
180
0
    return;
181
0
  EVP_MD_CTX_free(ctx->mdctx);
182
0
  freezero(ctx, sizeof(*ctx));
183
0
}
184
185
int
186
ssh_digest_memory(int alg, const void *m, size_t mlen, u_char *d, size_t dlen)
187
2.28k
{
188
2.28k
  const struct ssh_digest *digest = ssh_digest_by_alg(alg);
189
2.28k
  u_int mdlen;
190
191
2.28k
  if (digest == NULL)
192
0
    return SSH_ERR_INVALID_ARGUMENT;
193
2.28k
  if (dlen > UINT_MAX)
194
0
    return SSH_ERR_INVALID_ARGUMENT;
195
2.28k
  if (dlen < digest->digest_len)
196
0
    return SSH_ERR_INVALID_ARGUMENT;
197
2.28k
  mdlen = dlen;
198
2.28k
  if (!EVP_Digest(m, mlen, d, &mdlen, digest->mdfunc(), NULL))
199
0
    return SSH_ERR_LIBCRYPTO_ERROR;
200
2.28k
  return 0;
201
2.28k
}
202
203
int
204
ssh_digest_buffer(int alg, const struct sshbuf *b, u_char *d, size_t dlen)
205
2.24k
{
206
2.24k
  return ssh_digest_memory(alg, sshbuf_ptr(b), sshbuf_len(b), d, dlen);
207
2.24k
}
208
#endif /* WITH_OPENSSL */