1 /*
2 * ProFTPD - mod_auth_otp OpenSSL interface
3 * Copyright (c) 2015-2018 TJ Saunders
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18 *
19 * As a special exemption, TJ Saunders and other respective copyright holders
20 * give permission to link this program with OpenSSL, and distribute the
21 * resulting executable, without including the source code for OpenSSL in the
22 * source distribution.
23 */
24
25 #include "mod_auth_otp.h"
26 #include "crypto.h"
27
auth_otp_crypto_init(void)28 int auth_otp_crypto_init(void) {
29 return 0;
30 }
31
auth_otp_crypto_free(int flags)32 void auth_otp_crypto_free(int flags) {
33 /* Only call EVP_cleanup() et al if other OpenSSL-using modules are not
34 * present. If we called EVP_cleanup() here during a restart,
35 * and other modules want to use OpenSSL, we may be depriving those modules
36 * of OpenSSL functionality.
37 *
38 * At the moment, the modules known to use OpenSSL are mod_ldap,
39 * mod_sftp, mod_sql, and mod_sql_passwd, and mod_tls.
40 */
41 if (pr_module_get("mod_digest.c") == NULL &&
42 pr_module_get("mod_ldap.c") == NULL &&
43 pr_module_get("mod_proxy.c") == NULL &&
44 pr_module_get("mod_radius.c") == NULL &&
45 pr_module_get("mod_sftp.c") == NULL &&
46 pr_module_get("mod_sql.c") == NULL &&
47 pr_module_get("mod_sql_passwd.c") == NULL &&
48 pr_module_get("mod_tls.c") == NULL) {
49
50 ERR_free_strings();
51
52 #if OPENSSL_VERSION_NUMBER >= 0x10000001L
53 # if OPENSSL_VERSION_NUMBER >= 0x10100000L
54 /* The ERR_remove_state(0) usage is deprecated due to thread ID
55 * differences among platforms; see the OpenSSL-1.0.0c CHANGES file
56 * for details. So for new enough OpenSSL installations, use the
57 * proper way to clear the error queue state.
58 */
59 ERR_remove_thread_state(NULL);
60 # endif /* OpenSSL-1.1.x and later */
61 #else
62 ERR_remove_state(0);
63 #endif /* OpenSSL prior to 1.0.0-beta1 */
64
65 EVP_cleanup();
66 RAND_cleanup();
67 }
68 }
69
auth_otp_crypto_get_errors(void)70 const char *auth_otp_crypto_get_errors(void) {
71 unsigned int count = 0;
72 unsigned long e = ERR_get_error();
73 BIO *bio = NULL;
74 char *data = NULL;
75 long datalen;
76 const char *str = "(unknown)";
77
78 /* Use ERR_print_errors() and a memory BIO to build up a string with
79 * all of the error messages from the error queue.
80 */
81
82 if (e) {
83 bio = BIO_new(BIO_s_mem());
84 }
85
86 while (e) {
87 pr_signals_handle();
88 BIO_printf(bio, "\n (%u) %s", ++count, ERR_error_string(e, NULL));
89 e = ERR_get_error();
90 }
91
92 datalen = BIO_get_mem_data(bio, &data);
93 if (data) {
94 data[datalen] = '\0';
95 str = pstrndup(auth_otp_pool, data, datalen-1);
96 }
97
98 if (bio) {
99 BIO_free(bio);
100 }
101
102 return str;
103 }
104
auth_otp_hmac(const EVP_MD * md,const unsigned char * key,size_t key_len,const unsigned char * data,size_t data_len,unsigned char * mac,size_t * mac_len)105 int auth_otp_hmac(const EVP_MD *md, const unsigned char *key, size_t key_len,
106 const unsigned char *data, size_t data_len, unsigned char *mac,
107 size_t *mac_len) {
108
109 if ((key == NULL || key_len == 0) ||
110 (data == NULL || data_len == 0) ||
111 (mac == NULL || mac_len == NULL)) {
112 errno = EINVAL;
113 return -1;
114 }
115
116 if (HMAC(md, key, key_len, data, data_len, mac,
117 (unsigned int *) mac_len) == NULL) {
118 (void) pr_log_writefile(auth_otp_logfd, MOD_AUTH_OTP_VERSION,
119 "HMAC error: %s", auth_otp_crypto_get_errors());
120 errno = EPERM;
121 return -1;
122 }
123
124 return 0;
125 }
126