xref: /iperf/src/iperf_auth.c (revision f72054eb)
1 /*
2  * iperf, Copyright (c) 2014-2020, The Regents of the University of
3  * California, through Lawrence Berkeley National Laboratory (subject
4  * to receipt of any required approvals from the U.S. Dept. of
5  * Energy).  All rights reserved.
6  *
7  * If you have questions about your rights to use or distribute this
8  * software, please contact Berkeley Lab's Technology Transfer
9  * Department at [email protected].
10  *
11  * NOTICE.  This software is owned by the U.S. Department of Energy.
12  * As such, the U.S. Government has been granted for itself and others
13  * acting on its behalf a paid-up, nonexclusive, irrevocable,
14  * worldwide license in the Software to reproduce, prepare derivative
15  * works, and perform publicly and display publicly.  Beginning five
16  * (5) years after the date permission to assert copyright is obtained
17  * from the U.S. Department of Energy, and subject to any subsequent
18  * five (5) year renewals, the U.S. Government is granted for itself
19  * and others acting on its behalf a paid-up, nonexclusive,
20  * irrevocable, worldwide license in the Software to reproduce,
21  * prepare derivative works, distribute copies to the public, perform
22  * publicly and display publicly, and to permit others to do so.
23  *
24  * This code is distributed under a BSD style license, see the LICENSE file
25  * for complete information.
26  */
27 
28 #include "iperf_config.h"
29 
30 #include <string.h>
31 #include <assert.h>
32 #include <time.h>
33 #include <sys/types.h>
34 /* FreeBSD needs _WITH_GETLINE to enable the getline() declaration */
35 #define _WITH_GETLINE
36 #include <stdio.h>
37 #include <termios.h>
38 
39 #if defined(HAVE_SSL)
40 
41 #include <openssl/rsa.h>
42 #include <openssl/bio.h>
43 #include <openssl/pem.h>
44 #include <openssl/sha.h>
45 #include <openssl/buffer.h>
46 #include <openssl/err.h>
47 
48 const char *auth_text_format = "user: %s\npwd:  %s\nts:   %ld";
49 
50 void sha256(const char *string, char outputBuffer[65])
51 {
52     unsigned char hash[SHA256_DIGEST_LENGTH];
53     SHA256_CTX sha256;
54     SHA256_Init(&sha256);
55     SHA256_Update(&sha256, string, strlen(string));
56     SHA256_Final(hash, &sha256);
57     int i = 0;
58     for(i = 0; i < SHA256_DIGEST_LENGTH; i++)
59     {
60         sprintf(outputBuffer + (i * 2), "%02x", hash[i]);
61     }
62     outputBuffer[64] = 0;
63 }
64 
65 int check_authentication(const char *username, const char *password, const time_t ts, const char *filename){
66     time_t t = time(NULL);
67     time_t utc_seconds = mktime(localtime(&t));
68     if ( (utc_seconds - ts) > 10 || (utc_seconds - ts) < -10 ) {
69         return 1;
70     }
71 
72     char passwordHash[65];
73     char salted[strlen(username) + strlen(password) + 3];
74     sprintf(salted, "{%s}%s", username, password);
75     sha256(&salted[0], passwordHash);
76 
77     char *s_username, *s_password;
78     int i;
79     FILE *ptr_file;
80     char buf[1024];
81 
82     ptr_file =fopen(filename,"r");
83     if (!ptr_file)
84         return 2;
85 
86     while (fgets(buf,1024, ptr_file)){
87         //strip the \n or \r\n chars
88         for (i = 0; buf[i] != '\0'; i++){
89             if (buf[i] == '\n' || buf[i] == '\r'){
90                 buf[i] = '\0';
91                 break;
92             }
93         }
94         //skip empty / not completed / comment lines
95         if (strlen(buf) == 0 || strchr(buf, ',') == NULL || buf[0] == '#'){
96             continue;
97         }
98         s_username = strtok(buf, ",");
99         s_password = strtok(NULL, ",");
100         if (strcmp( username, s_username ) == 0 && strcmp( passwordHash, s_password ) == 0){
101             fclose(ptr_file);
102             return 0;
103         }
104     }
105     fclose(ptr_file);
106     return 3;
107 }
108 
109 
110 int Base64Encode(const unsigned char* buffer, const size_t length, char** b64text) { //Encodes a binary safe base 64 string
111     BIO *bio, *b64;
112     BUF_MEM *bufferPtr;
113 
114     b64 = BIO_new(BIO_f_base64());
115     bio = BIO_new(BIO_s_mem());
116     bio = BIO_push(b64, bio);
117 
118     BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); //Ignore newlines - write everything in one line
119     BIO_write(bio, buffer, length);
120     BIO_flush(bio);
121     BIO_get_mem_ptr(bio, &bufferPtr);
122     *b64text = strndup( (*bufferPtr).data, (*bufferPtr).length );
123     BIO_free_all(bio);
124 
125     return (0); //success
126 }
127 
128 size_t calcDecodeLength(const char* b64input) { //Calculates the length of a decoded string
129     size_t len = strlen(b64input), padding = 0;
130     if (b64input[len-1] == '=' && b64input[len-2] == '=') //last two chars are =
131         padding = 2;
132     else if (b64input[len-1] == '=') //last char is =
133         padding = 1;
134 
135     return (len*3)/4 - padding;
136 }
137 
138 int Base64Decode(const char* b64message, unsigned char** buffer, size_t* length) { //Decodes a base64 encoded string
139     BIO *bio, *b64;
140 
141     int decodeLen = calcDecodeLength(b64message);
142     *buffer = (unsigned char*)malloc(decodeLen + 1);
143     (*buffer)[decodeLen] = '\0';
144 
145     bio = BIO_new_mem_buf(b64message, -1);
146     b64 = BIO_new(BIO_f_base64());
147     bio = BIO_push(b64, bio);
148 
149     BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); //Do not use newlines to flush buffer
150     *length = BIO_read(bio, *buffer, strlen(b64message));
151     assert(*length == decodeLen); //length should equal decodeLen, else something went horribly wrong
152     BIO_free_all(bio);
153 
154     return (0); //success
155 }
156 
157 EVP_PKEY *load_pubkey_from_file(const char *file) {
158     BIO *key = NULL;
159     EVP_PKEY *pkey = NULL;
160 
161     if (file) {
162       key = BIO_new_file(file, "r");
163       pkey = PEM_read_bio_PUBKEY(key, NULL, NULL, NULL);
164 
165       BIO_free(key);
166     }
167     return (pkey);
168 }
169 
170 EVP_PKEY *load_pubkey_from_base64(const char *buffer) {
171     unsigned char *key = NULL;
172     size_t key_len;
173     Base64Decode(buffer, &key, &key_len);
174 
175     BIO* bio = BIO_new(BIO_s_mem());
176     BIO_write(bio, key, key_len);
177     EVP_PKEY *pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
178     BIO_free(bio);
179     return (pkey);
180 }
181 
182 EVP_PKEY *load_privkey_from_file(const char *file) {
183     BIO *key = NULL;
184     EVP_PKEY *pkey = NULL;
185 
186     if (file) {
187       key = BIO_new_file(file, "r");
188       pkey = PEM_read_bio_PrivateKey(key, NULL, NULL, NULL);
189 
190       BIO_free(key);
191     }
192     return (pkey);
193 }
194 
195 EVP_PKEY *load_privkey_from_base64(const char *buffer) {
196     unsigned char *key = NULL;
197     size_t key_len;
198     Base64Decode(buffer, &key, &key_len);
199 
200     BIO* bio = BIO_new(BIO_s_mem());
201     BIO_write(bio, key, key_len);
202     EVP_PKEY *pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
203     BIO_free(bio);
204     return (pkey);
205 }
206 
207 int test_load_pubkey_from_file(const char *file){
208     EVP_PKEY *key = load_pubkey_from_file(file);
209     if (key == NULL){
210         return -1;
211     }
212     EVP_PKEY_free(key);
213     return 0;
214 }
215 
216 int test_load_private_key_from_file(const char *file){
217     EVP_PKEY *key = load_privkey_from_file(file);
218     if (key == NULL){
219         return -1;
220     }
221     EVP_PKEY_free(key);
222     return 0;
223 }
224 
225 int encrypt_rsa_message(const char *plaintext, EVP_PKEY *public_key, unsigned char **encryptedtext) {
226     RSA *rsa = NULL;
227     unsigned char *rsa_buffer = NULL, pad = RSA_PKCS1_PADDING;
228     int keysize, encryptedtext_len, rsa_buffer_len;
229 
230     rsa = EVP_PKEY_get1_RSA(public_key);
231     keysize = RSA_size(rsa);
232 
233     rsa_buffer  = OPENSSL_malloc(keysize * 2);
234     *encryptedtext = (unsigned char*)OPENSSL_malloc(keysize);
235 
236     BIO *bioBuff   = BIO_new_mem_buf((void*)plaintext, (int)strlen(plaintext));
237     rsa_buffer_len = BIO_read(bioBuff, rsa_buffer, keysize * 2);
238     encryptedtext_len = RSA_public_encrypt(rsa_buffer_len, rsa_buffer, *encryptedtext, rsa, pad);
239 
240     RSA_free(rsa);
241     OPENSSL_free(rsa_buffer);
242     BIO_free(bioBuff);
243 
244     if (encryptedtext_len < 0) {
245       /* We probably shoudln't be printing stuff like this */
246       fprintf(stderr, "%s\n", ERR_error_string(ERR_get_error(), NULL));
247     }
248 
249     return encryptedtext_len;
250 }
251 
252 int decrypt_rsa_message(const unsigned char *encryptedtext, const int encryptedtext_len, EVP_PKEY *private_key, unsigned char **plaintext) {
253     RSA *rsa = NULL;
254     unsigned char *rsa_buffer = NULL, pad = RSA_PKCS1_PADDING;
255     int plaintext_len, rsa_buffer_len, keysize;
256 
257     rsa = EVP_PKEY_get1_RSA(private_key);
258 
259     keysize = RSA_size(rsa);
260     rsa_buffer  = OPENSSL_malloc(keysize * 2);
261     *plaintext = (unsigned char*)OPENSSL_malloc(keysize);
262 
263     BIO *bioBuff   = BIO_new_mem_buf((void*)encryptedtext, encryptedtext_len);
264     rsa_buffer_len = BIO_read(bioBuff, rsa_buffer, keysize * 2);
265     plaintext_len = RSA_private_decrypt(rsa_buffer_len, rsa_buffer, *plaintext, rsa, pad);
266 
267     RSA_free(rsa);
268     OPENSSL_free(rsa_buffer);
269     BIO_free(bioBuff);
270 
271     if (plaintext_len < 0) {
272       /* We probably shoudln't be printing stuff like this */
273       fprintf(stderr, "%s\n", ERR_error_string(ERR_get_error(), NULL));
274     }
275 
276     return plaintext_len;
277 }
278 
279 int encode_auth_setting(const char *username, const char *password, EVP_PKEY *public_key, char **authtoken){
280     time_t t = time(NULL);
281     time_t utc_seconds = mktime(localtime(&t));
282 
283     /*
284      * Compute a pessimistic/conservative estimate of storage required.
285      * It's OK to allocate too much storage but too little is bad.
286      */
287     const int text_len = strlen(auth_text_format) + strlen(username) + strlen(password) + 32;
288     char *text = (char *) calloc(text_len, sizeof(char));
289     if (text == NULL) {
290 	return -1;
291     }
292     snprintf(text, text_len, auth_text_format, username, password, utc_seconds);
293 
294     unsigned char *encrypted = NULL;
295     int encrypted_len;
296     encrypted_len = encrypt_rsa_message(text, public_key, &encrypted);
297     free(text);
298     if (encrypted_len < 0) {
299       return -1;
300     }
301     Base64Encode(encrypted, encrypted_len, authtoken);
302     OPENSSL_free(encrypted);
303 
304     return (0); //success
305 }
306 
307 int decode_auth_setting(int enable_debug, char *authtoken, EVP_PKEY *private_key, char **username, char **password, time_t *ts){
308     unsigned char *encrypted_b64 = NULL;
309     size_t encrypted_len_b64;
310     Base64Decode(authtoken, &encrypted_b64, &encrypted_len_b64);
311 
312     unsigned char *plaintext = NULL;
313     int plaintext_len;
314     plaintext_len = decrypt_rsa_message(encrypted_b64, encrypted_len_b64, private_key, &plaintext);
315     free(encrypted_b64);
316     if (plaintext_len < 0) {
317         return -1;
318     }
319     plaintext[plaintext_len] = '\0';
320 
321     char *s_username, *s_password;
322     s_username = (char *) calloc(plaintext_len, sizeof(char));
323     if (s_username == NULL) {
324 	return -1;
325     }
326     s_password = (char *) calloc(plaintext_len, sizeof(char));
327     if (s_password == NULL) {
328 	free(s_username);
329 	return -1;
330     }
331 
332     int rc = sscanf((char *) plaintext, auth_text_format, s_username, s_password, ts);
333     if (rc != 3) {
334 	free(s_password);
335 	free(s_username);
336 	return -1;
337     }
338 
339     if (enable_debug) {
340         printf("Auth Token Content:\n%s\n", plaintext);
341         printf("Auth Token Credentials:\n--> %s %s\n", s_username, s_password);
342     }
343     *username = s_username;
344     *password = s_password;
345     OPENSSL_free(plaintext);
346     return (0);
347 }
348 
349 #endif //HAVE_SSL
350 
351 ssize_t iperf_getpass (char **lineptr, size_t *n, FILE *stream) {
352     struct termios old, new;
353     ssize_t nread;
354 
355     /* Turn echoing off and fail if we can't. */
356     if (tcgetattr (fileno (stream), &old) != 0)
357         return -1;
358     new = old;
359     new.c_lflag &= ~ECHO;
360     if (tcsetattr (fileno (stream), TCSAFLUSH, &new) != 0)
361         return -1;
362 
363     /* Read the password. */
364     printf("Password: ");
365     nread = getline (lineptr, n, stream);
366 
367     /* Restore terminal. */
368     (void) tcsetattr (fileno (stream), TCSAFLUSH, &old);
369 
370     //strip the \n or \r\n chars
371     char *buf = *lineptr;
372     int i;
373     for (i = 0; buf[i] != '\0'; i++){
374         if (buf[i] == '\n' || buf[i] == '\r'){
375             buf[i] = '\0';
376             break;
377         }
378     }
379 
380     return nread;
381 }
382 
383 
384