1 /* $NetBSD: md.c,v 1.7 2025/01/26 16:25:37 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 27 isc_md_t * 28 isc_md_new(void) { 29 isc_md_t *md = EVP_MD_CTX_new(); 30 RUNTIME_CHECK(md != NULL); 31 return md; 32 } 33 34 void 35 isc_md_free(isc_md_t *md) { 36 if (md == NULL) { 37 return; 38 } 39 40 EVP_MD_CTX_free(md); 41 } 42 43 isc_result_t 44 isc_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 59 isc_result_t 60 isc_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 71 isc_result_t 72 isc_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 87 isc_result_t 88 isc_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 100 const isc_md_type_t * 101 isc_md_get_md_type(isc_md_t *md) { 102 REQUIRE(md != NULL); 103 104 return EVP_MD_CTX_get0_md(md); 105 } 106 107 size_t 108 isc_md_get_size(isc_md_t *md) { 109 REQUIRE(md != NULL); 110 111 return EVP_MD_CTX_size(md); 112 } 113 114 size_t 115 isc_md_get_block_size(isc_md_t *md) { 116 REQUIRE(md != NULL); 117 118 return EVP_MD_CTX_block_size(md); 119 } 120 121 size_t 122 isc_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 133 size_t 134 isc_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 145 isc_result_t 146 isc_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 } 167 end: 168 isc_md_free(md); 169 170 return res; 171 } 172 173 #ifndef UNIT_TESTING 174 const isc_md_type_t *isc__md_md5 = NULL; 175 const isc_md_type_t *isc__md_sha1 = NULL; 176 const isc_md_type_t *isc__md_sha224 = NULL; 177 const isc_md_type_t *isc__md_sha256 = NULL; 178 const isc_md_type_t *isc__md_sha384 = NULL; 179 const isc_md_type_t *isc__md_sha512 = NULL; 180 181 #if OPENSSL_VERSION_NUMBER >= 0x30000000L 182 #define md_register_algorithm(alg, algname) \ 183 { \ 184 REQUIRE(isc__md_##alg == NULL); \ 185 isc__md_##alg = EVP_MD_fetch(NULL, algname, NULL); \ 186 if (isc__md_##alg == NULL) { \ 187 ERR_clear_error(); \ 188 } \ 189 } 190 191 #define md_unregister_algorithm(alg) \ 192 { \ 193 if (isc__md_##alg != NULL) { \ 194 EVP_MD_free(*(isc_md_type_t **)&isc__md_##alg); \ 195 isc__md_##alg = NULL; \ 196 } \ 197 } 198 199 #else 200 #define md_register_algorithm(alg, algname) \ 201 { \ 202 isc__md_##alg = EVP_##alg(); \ 203 if (isc__md_##alg == NULL) { \ 204 ERR_clear_error(); \ 205 } \ 206 } 207 #define md_unregister_algorithm(alg) 208 #endif 209 210 void 211 isc__md_initialize(void) { 212 md_register_algorithm(md5, "MD5"); 213 md_register_algorithm(sha1, "SHA1"); 214 md_register_algorithm(sha224, "SHA224"); 215 md_register_algorithm(sha256, "SHA256"); 216 md_register_algorithm(sha384, "SHA384"); 217 md_register_algorithm(sha512, "SHA512"); 218 } 219 220 void 221 isc__md_shutdown(void) { 222 md_unregister_algorithm(sha512); 223 md_unregister_algorithm(sha384); 224 md_unregister_algorithm(sha256); 225 md_unregister_algorithm(sha224); 226 md_unregister_algorithm(sha1); 227 md_unregister_algorithm(md5); 228 } 229 230 #endif /* UNIT_TESTING */ 231