1 /* $NetBSD: ossl_digest.c,v 1.2 2026/05/09 18:49:23 christos Exp $ */ 2 3 /*++ 4 /* NAME 5 /* ossl_digest 3 6 /* SUMMARY 7 /* OpenSSL message digest wrapper 8 /* SYNOPSIS 9 /* #define USE_TLS 10 /* 11 /* #include <ossl_digest.h> 12 /* 13 /* OSSL_DGST *ossl_digest_new( 14 /* const char *alg_name) 15 /* 16 /* int ossl_digest_data( 17 /* OSSL_DGST *dgst, 18 /* const void *data, 19 /* ssize_t data_len, 20 /* VSTRING *out); 21 /* 22 /* ARGV *ossl_digest_get_errors(void) 23 /* 24 /* ARGV *ossl_digest_log_errors( 25 /* void (*logger)(const char *,...)) 26 /* 27 /* ssize_t ossl_digest_get_size( 28 /* OSSL_DGST *dgst) 29 /* 30 /* void ossl_digest_free( 31 /* OSSL_DGST *dgst) 32 /* DESCRIPTION 33 /* ossl_digest_new() allocates a wrapper for the named message 34 /* digest algorithm. This wrapper can be used in multiple successive 35 /* calls to compute a digest, and can be disposed of with 36 /* ossl_digest_free(). 37 /* 38 /* ossl_digest_data() uses the specified message digest wrapper to 39 /* compute a digest over the specified data. 40 /* 41 /* ossl_digest_get_errors() dumps and clears the OpenSSL error stack. 42 /* Each stack entry is copied to one ARGV element. NOTE: The caller 43 /* should be prepared for the call to return an empty result, 44 /* and always report their own error info. 45 /* 46 /* ossl_digest_log_errors() logs and clears the OpenSSL error stack. 47 /* Each stack entry is logged by the specified function. NOTE: 48 /* The caller should be prepared for the call to return an empty 49 /* result, and log their own error message. 50 /* 51 /* ossl_digest_get_size() returns the output byte count for the 52 /* specified message digest wrapper. 53 /* 54 /* ossl_digest_free() releases storage allocated for or by the 55 /* specified message wrapper. 56 /* DIAGNOSTICS 57 /* Panic: ossl_digest_data() was called with an invalid data_len 58 /* argument; an ossl_digest_free() argument was not created with 59 /* ossl_digest_new(). 60 /* 61 /* ossl_digest_new() returns NULL after error. ossl_digest_data() 62 /* returns 0 after success, -1 after error. 63 /* LICENSE 64 /* .ad 65 /* .fi 66 /* The Secure Mailer license must be distributed with this software. 67 /* AUTHOR(S) 68 /* Wietse Venema 69 /* porcupine.org 70 /*--*/ 71 72 #ifdef USE_TLS 73 74 /* 75 * System library. 76 */ 77 #include <sys_defs.h> 78 79 /* 80 * OpenSSL library. 81 */ 82 #include <openssl/err.h> 83 #include <openssl/evp.h> 84 85 /* 86 * Utility library. 87 */ 88 #include <msg.h> 89 #include <mymalloc.h> 90 #include <ossl_digest.h> 91 #include <vstring.h> 92 93 #ifndef OPENSSL_VERSION_PREREQ 94 #define OPENSSL_VERSION_PREREQ(m,n) 0 95 #endif 96 97 /* 98 * OpenSSL 1.1.1 compatibility crutches. Note: EVP_get_digestbyname() 99 * returns const EVP_MD * which can't be passed to EVP_MD_free(EVP_MD *). 100 */ 101 #if !OPENSSL_VERSION_PREREQ(3,0) 102 #define EVP_MD_fetch(ct, alg_name, pr) EVP_get_digestbyname(alg_name) 103 #define BC_CONST const 104 #define EVP_MD_free(m) /* */ 105 #define EVP_MD_get_size EVP_MD_size 106 #else 107 #define BC_CONST /* */ 108 #endif 109 110 /* 111 * Opaque object. 112 */ 113 struct OSSL_DGST { 114 EVP_MD_CTX *mdctx; 115 BC_CONST EVP_MD *dgst_alg; 116 }; 117 118 /* 119 * SLMs. 120 */ 121 #define STR(x) vstring_str(x) 122 #define LEN(x) VSTRING_LEN(x) 123 124 /* ossl_digest_new - create OpenSSL digest wrapper */ 125 126 OSSL_DGST *ossl_digest_new(const char *alg_name) 127 { 128 OSSL_DGST *dgst = (OSSL_DGST *) mymalloc(sizeof(*dgst)); 129 130 /* 131 * https://docs.openssl.org/3.3/man7/ossl-guide-libcrypto-introduction 132 * "If you perform the same operation many times with the same algorithm 133 * then it is recommended to use a single explicit fetch of the algorithm 134 * and then reuse the explicitly fetched algorithm each subsequent time. 135 * This will typically be faster than implicitly fetching the algorithm 136 * every time you use it". 137 * 138 * That same text mentions that calling, for example, EVP_sha256(3), uses 139 * implicit fetching. 140 */ 141 if ((dgst->dgst_alg = EVP_MD_fetch(NULL, alg_name, NULL)) != 0) { 142 if ((dgst->mdctx = EVP_MD_CTX_new()) != 0) { 143 /* Success. */ 144 return (dgst); 145 } 146 EVP_MD_free(dgst->dgst_alg); 147 } 148 /* Failure. */ 149 myfree(dgst); 150 return (0); 151 } 152 153 /* ossl_digest_data - digest one data buffer */ 154 155 int ossl_digest_data(OSSL_DGST *dgst, const void *data, 156 ssize_t data_len, VSTRING *out) 157 { 158 unsigned int out_len; 159 160 if (data_len < 0) 161 msg_panic("ossl_digest_data: bad data_len %ld", (long) data_len); 162 163 VSTRING_RESET(out); 164 VSTRING_SPACE(out, EVP_MD_get_size(dgst->dgst_alg)); 165 if (EVP_DigestInit_ex(dgst->mdctx, dgst->dgst_alg, 0) != 1 166 || EVP_DigestUpdate(dgst->mdctx, data, data_len) != 1 167 || EVP_DigestFinal_ex(dgst->mdctx, (void *) STR(out), 168 &out_len) != 1) 169 return (-1); 170 vstring_set_payload_size(out, out_len); 171 return (0); 172 } 173 174 /* ossl_digest_get_size - determine digest output byte count */ 175 176 ssize_t ossl_digest_get_size(OSSL_DGST *dgst) 177 { 178 return (EVP_MD_get_size(dgst->dgst_alg)); 179 } 180 181 /* ossl_digest_get_errors - export and clear OpenSSL error stack */ 182 183 ARGV *ossl_digest_get_errors(void) 184 { 185 ARGV *argv = argv_alloc(1); 186 VSTRING *tmp = vstring_alloc(100); 187 unsigned long err; 188 char buffer[1024]; /* XXX */ 189 const char *file; 190 const char *data; 191 int line; 192 int flags; 193 194 /* 195 * Shamelessly copied from Postfix TLS library. 196 */ 197 #if OPENSSL_VERSION_PREREQ(3,0) 198 /* XXX: We're ignoring the function name, do we want to log it? */ 199 #define ERRGET(fi, l, d, fl) ERR_get_error_all(fi, l, 0, d, fl) 200 #else 201 #define ERRGET(fi, l, d, fl) ERR_get_error_line_data(fi, l, d, fl) 202 #endif 203 204 while ((err = ERRGET(&file, &line, &data, &flags)) != 0) { 205 ERR_error_string_n(err, buffer, sizeof(buffer)); 206 if (flags & ERR_TXT_STRING) 207 vstring_sprintf(tmp, "%s:%s:%d:%s:", 208 buffer, file, line, data); 209 else 210 vstring_sprintf(tmp, "%s:%s:%d:", buffer, file, line); 211 argv_add(argv, STR(tmp), (char *) 0); 212 } 213 vstring_free(tmp); 214 return (argv); 215 } 216 217 /* ossl_digest_log_errors - log and clear OpenSSL error stack */ 218 219 void ossl_digest_log_errors(void (*logger) (const char *,...)) 220 { 221 unsigned long err; 222 char buffer[1024]; /* XXX */ 223 const char *file; 224 const char *data; 225 int line; 226 int flags; 227 228 while ((err = ERRGET(&file, &line, &data, &flags)) != 0) { 229 ERR_error_string_n(err, buffer, sizeof(buffer)); 230 if (flags & ERR_TXT_STRING) 231 logger("%s:%s:%d:%s:", buffer, file, line, data); 232 else 233 logger("%s:%s:%d:", buffer, file, line); 234 } 235 } 236 237 /* ossl_digest_free - dispose of digest wrapper */ 238 239 void ossl_digest_free(OSSL_DGST *dgst) 240 { 241 EVP_MD_CTX_destroy(dgst->mdctx); 242 EVP_MD_free(dgst->dgst_alg); 243 myfree(dgst); 244 } 245 246 #endif /* USE_TLS */ 247