1/*	$NetBSD: md.c,v 1.6 2024/02/21 22:52:28 christos Exp $	*/
2
3/*
4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5 *
6 * SPDX-License-Identifier: MPL-2.0
7 *
8 * This Source Code Form is subject to the terms of the Mozilla Public
9 * License, v. 2.0. If a copy of the MPL was not distributed with this
10 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11 *
12 * See the COPYRIGHT file distributed with this work for additional
13 * information regarding copyright ownership.
14 */
15
16#include <stdio.h>
17
18#include <openssl/err.h>
19#include <openssl/evp.h>
20#include <openssl/opensslv.h>
21
22#include <isc/md.h>
23#include <isc/util.h>
24
25#include "openssl_shim.h"
26
27isc_md_t *
28isc_md_new(void) {
29	isc_md_t *md = EVP_MD_CTX_new();
30	RUNTIME_CHECK(md != NULL);
31	return (md);
32}
33
34void
35isc_md_free(isc_md_t *md) {
36	if (md == NULL) {
37		return;
38	}
39
40	EVP_MD_CTX_free(md);
41}
42
43isc_result_t
44isc_md_init(isc_md_t *md, const isc_md_type_t *md_type) {
45	REQUIRE(md != NULL);
46
47	if (md_type == NULL) {
48		return (ISC_R_NOTIMPLEMENTED);
49	}
50
51	if (EVP_DigestInit_ex(md, md_type, NULL) != 1) {
52		ERR_clear_error();
53		return (ISC_R_CRYPTOFAILURE);
54	}
55
56	return (ISC_R_SUCCESS);
57}
58
59isc_result_t
60isc_md_reset(isc_md_t *md) {
61	REQUIRE(md != NULL);
62
63	if (EVP_MD_CTX_reset(md) != 1) {
64		ERR_clear_error();
65		return (ISC_R_CRYPTOFAILURE);
66	}
67
68	return (ISC_R_SUCCESS);
69}
70
71isc_result_t
72isc_md_update(isc_md_t *md, const unsigned char *buf, const size_t len) {
73	REQUIRE(md != NULL);
74
75	if (buf == NULL || len == 0) {
76		return (ISC_R_SUCCESS);
77	}
78
79	if (EVP_DigestUpdate(md, buf, len) != 1) {
80		ERR_clear_error();
81		return (ISC_R_CRYPTOFAILURE);
82	}
83
84	return (ISC_R_SUCCESS);
85}
86
87isc_result_t
88isc_md_final(isc_md_t *md, unsigned char *digest, unsigned int *digestlen) {
89	REQUIRE(md != NULL);
90	REQUIRE(digest != NULL);
91
92	if (EVP_DigestFinal_ex(md, digest, digestlen) != 1) {
93		ERR_clear_error();
94		return (ISC_R_CRYPTOFAILURE);
95	}
96
97	return (ISC_R_SUCCESS);
98}
99
100const isc_md_type_t *
101isc_md_get_md_type(isc_md_t *md) {
102	REQUIRE(md != NULL);
103
104	return (EVP_MD_CTX_get0_md(md));
105}
106
107size_t
108isc_md_get_size(isc_md_t *md) {
109	REQUIRE(md != NULL);
110
111	return (EVP_MD_CTX_size(md));
112}
113
114size_t
115isc_md_get_block_size(isc_md_t *md) {
116	REQUIRE(md != NULL);
117
118	return (EVP_MD_CTX_block_size(md));
119}
120
121size_t
122isc_md_type_get_size(const isc_md_type_t *md_type) {
123	STATIC_ASSERT(ISC_MAX_MD_SIZE >= EVP_MAX_MD_SIZE,
124		      "Change ISC_MAX_MD_SIZE to be greater than or equal to "
125		      "EVP_MAX_MD_SIZE");
126	if (md_type != NULL) {
127		return ((size_t)EVP_MD_size(md_type));
128	}
129
130	return (ISC_MAX_MD_SIZE);
131}
132
133size_t
134isc_md_type_get_block_size(const isc_md_type_t *md_type) {
135	STATIC_ASSERT(ISC_MAX_MD_SIZE >= EVP_MAX_MD_SIZE,
136		      "Change ISC_MAX_MD_SIZE to be greater than or equal to "
137		      "EVP_MAX_MD_SIZE");
138	if (md_type != NULL) {
139		return ((size_t)EVP_MD_block_size(md_type));
140	}
141
142	return (ISC_MAX_MD_SIZE);
143}
144
145isc_result_t
146isc_md(const isc_md_type_t *md_type, const unsigned char *buf, const size_t len,
147       unsigned char *digest, unsigned int *digestlen) {
148	isc_md_t *md;
149	isc_result_t res;
150
151	md = isc_md_new();
152
153	res = isc_md_init(md, md_type);
154	if (res != ISC_R_SUCCESS) {
155		goto end;
156	}
157
158	res = isc_md_update(md, buf, len);
159	if (res != ISC_R_SUCCESS) {
160		goto end;
161	}
162
163	res = isc_md_final(md, digest, digestlen);
164	if (res != ISC_R_SUCCESS) {
165		goto end;
166	}
167end:
168	isc_md_free(md);
169
170	return (res);
171}
172
173#define md_register_algorithm(alg)                        \
174	const isc_md_type_t *isc__md_##alg(void) {        \
175		const isc_md_type_t *value = EVP_##alg(); \
176		if (value == NULL) {                      \
177			ERR_clear_error();                \
178		}                                         \
179		return (value);                           \
180	}
181
182md_register_algorithm(md5);
183md_register_algorithm(sha1);
184md_register_algorithm(sha224);
185md_register_algorithm(sha256);
186md_register_algorithm(sha384);
187md_register_algorithm(sha512);
188