• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 TTD@lbl.gov.
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 #include <inttypes.h>
39 #include <stdint.h>
40 
41 #if defined(HAVE_SSL)
42 
43 #include <openssl/rsa.h>
44 #include <openssl/bio.h>
45 #include <openssl/pem.h>
46 #include <openssl/sha.h>
47 #include <openssl/buffer.h>
48 #include <openssl/err.h>
49 
50 const char *auth_text_format = "user: %s\npwd:  %s\nts:   %"PRId64;
51 
sha256(const char * string,char outputBuffer[65])52 void sha256(const char *string, char outputBuffer[65])
53 {
54     unsigned char hash[SHA256_DIGEST_LENGTH];
55     SHA256_CTX sha256;
56     SHA256_Init(&sha256);
57     SHA256_Update(&sha256, string, strlen(string));
58     SHA256_Final(hash, &sha256);
59     int i = 0;
60     for(i = 0; i < SHA256_DIGEST_LENGTH; i++)
61     {
62         sprintf(outputBuffer + (i * 2), "%02x", hash[i]);
63     }
64     outputBuffer[64] = 0;
65 }
66 
check_authentication(const char * username,const char * password,const time_t ts,const char * filename,int skew_threshold)67 int check_authentication(const char *username, const char *password, const time_t ts, const char *filename, int skew_threshold){
68     time_t t = time(NULL);
69     time_t utc_seconds = mktime(localtime(&t));
70     if ( (utc_seconds - ts) > skew_threshold || (utc_seconds - ts) < -skew_threshold ) {
71         return 1;
72     }
73 
74     char passwordHash[65];
75     char salted[strlen(username) + strlen(password) + 3];
76     sprintf(salted, "{%s}%s", username, password);
77     sha256(&salted[0], passwordHash);
78 
79     char *s_username, *s_password;
80     int i;
81     FILE *ptr_file;
82     char buf[1024];
83 
84     ptr_file =fopen(filename,"r");
85     if (!ptr_file)
86         return 2;
87 
88     while (fgets(buf,1024, ptr_file)){
89         //strip the \n or \r\n chars
90         for (i = 0; buf[i] != '\0'; i++){
91             if (buf[i] == '\n' || buf[i] == '\r'){
92                 buf[i] = '\0';
93                 break;
94             }
95         }
96         //skip empty / not completed / comment lines
97         if (strlen(buf) == 0 || strchr(buf, ',') == NULL || buf[0] == '#'){
98             continue;
99         }
100         s_username = strtok(buf, ",");
101         s_password = strtok(NULL, ",");
102         if (strcmp( username, s_username ) == 0 && strcmp( passwordHash, s_password ) == 0){
103             fclose(ptr_file);
104             return 0;
105         }
106     }
107     fclose(ptr_file);
108     return 3;
109 }
110 
111 
Base64Encode(const unsigned char * buffer,const size_t length,char ** b64text)112 int Base64Encode(const unsigned char* buffer, const size_t length, char** b64text) { //Encodes a binary safe base 64 string
113     BIO *bio, *b64;
114     BUF_MEM *bufferPtr;
115 
116     b64 = BIO_new(BIO_f_base64());
117     bio = BIO_new(BIO_s_mem());
118     bio = BIO_push(b64, bio);
119 
120     BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); //Ignore newlines - write everything in one line
121     BIO_write(bio, buffer, length);
122     BIO_flush(bio);
123     BIO_get_mem_ptr(bio, &bufferPtr);
124     *b64text = strndup( (*bufferPtr).data, (*bufferPtr).length );
125     BIO_free_all(bio);
126 
127     return (0); //success
128 }
129 
calcDecodeLength(const char * b64input)130 size_t calcDecodeLength(const char* b64input) { //Calculates the length of a decoded string
131     size_t len = strlen(b64input), padding = 0;
132     if (b64input[len-1] == '=' && b64input[len-2] == '=') //last two chars are =
133         padding = 2;
134     else if (b64input[len-1] == '=') //last char is =
135         padding = 1;
136 
137     return (len*3)/4 - padding;
138 }
139 
Base64Decode(const char * b64message,unsigned char ** buffer,size_t * length)140 int Base64Decode(const char* b64message, unsigned char** buffer, size_t* length) { //Decodes a base64 encoded string
141     BIO *bio, *b64;
142 
143     int decodeLen = calcDecodeLength(b64message);
144     *buffer = (unsigned char*)malloc(decodeLen + 1);
145     (*buffer)[decodeLen] = '\0';
146 
147     bio = BIO_new_mem_buf(b64message, -1);
148     b64 = BIO_new(BIO_f_base64());
149     bio = BIO_push(b64, bio);
150 
151     BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); //Do not use newlines to flush buffer
152     *length = BIO_read(bio, *buffer, strlen(b64message));
153     assert(*length == decodeLen); //length should equal decodeLen, else something went horribly wrong
154     BIO_free_all(bio);
155 
156     return (0); //success
157 }
158 
load_pubkey_from_file(const char * file)159 EVP_PKEY *load_pubkey_from_file(const char *file) {
160     BIO *key = NULL;
161     EVP_PKEY *pkey = NULL;
162 
163     if (file) {
164       key = BIO_new_file(file, "r");
165       pkey = PEM_read_bio_PUBKEY(key, NULL, NULL, NULL);
166 
167       BIO_free(key);
168     }
169     return (pkey);
170 }
171 
load_pubkey_from_base64(const char * buffer)172 EVP_PKEY *load_pubkey_from_base64(const char *buffer) {
173     unsigned char *key = NULL;
174     size_t key_len;
175     Base64Decode(buffer, &key, &key_len);
176 
177     BIO* bio = BIO_new(BIO_s_mem());
178     BIO_write(bio, key, key_len);
179     free(key);
180     EVP_PKEY *pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
181     BIO_free(bio);
182     return (pkey);
183 }
184 
load_privkey_from_file(const char * file)185 EVP_PKEY *load_privkey_from_file(const char *file) {
186     BIO *key = NULL;
187     EVP_PKEY *pkey = NULL;
188 
189     if (file) {
190       key = BIO_new_file(file, "r");
191       pkey = PEM_read_bio_PrivateKey(key, NULL, NULL, NULL);
192 
193       BIO_free(key);
194     }
195     return (pkey);
196 }
197 
load_privkey_from_base64(const char * buffer)198 EVP_PKEY *load_privkey_from_base64(const char *buffer) {
199     unsigned char *key = NULL;
200     size_t key_len;
201     Base64Decode(buffer, &key, &key_len);
202 
203     BIO* bio = BIO_new(BIO_s_mem());
204     BIO_write(bio, key, key_len);
205     free(key);
206     EVP_PKEY *pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
207     BIO_free(bio);
208     return (pkey);
209 }
210 
test_load_pubkey_from_file(const char * file)211 int test_load_pubkey_from_file(const char *file){
212     EVP_PKEY *key = load_pubkey_from_file(file);
213     if (key == NULL){
214         return -1;
215     }
216     EVP_PKEY_free(key);
217     return 0;
218 }
219 
test_load_private_key_from_file(const char * file)220 int test_load_private_key_from_file(const char *file){
221     EVP_PKEY *key = load_privkey_from_file(file);
222     if (key == NULL){
223         return -1;
224     }
225     EVP_PKEY_free(key);
226     return 0;
227 }
228 
encrypt_rsa_message(const char * plaintext,EVP_PKEY * public_key,unsigned char ** encryptedtext)229 int encrypt_rsa_message(const char *plaintext, EVP_PKEY *public_key, unsigned char **encryptedtext) {
230     RSA *rsa = NULL;
231     unsigned char *rsa_buffer = NULL, pad = RSA_PKCS1_PADDING;
232     int keysize, encryptedtext_len, rsa_buffer_len;
233 
234     rsa = EVP_PKEY_get1_RSA(public_key);
235     keysize = RSA_size(rsa);
236 
237     rsa_buffer  = OPENSSL_malloc(keysize * 2);
238     *encryptedtext = (unsigned char*)OPENSSL_malloc(keysize);
239 
240     BIO *bioBuff   = BIO_new_mem_buf((void*)plaintext, (int)strlen(plaintext));
241     rsa_buffer_len = BIO_read(bioBuff, rsa_buffer, keysize * 2);
242     encryptedtext_len = RSA_public_encrypt(rsa_buffer_len, rsa_buffer, *encryptedtext, rsa, pad);
243 
244     RSA_free(rsa);
245     OPENSSL_free(rsa_buffer);
246     BIO_free(bioBuff);
247 
248     if (encryptedtext_len < 0) {
249       /* We probably shoudln't be printing stuff like this */
250       fprintf(stderr, "%s\n", ERR_error_string(ERR_get_error(), NULL));
251     }
252 
253     return encryptedtext_len;
254 }
255 
decrypt_rsa_message(const unsigned char * encryptedtext,const int encryptedtext_len,EVP_PKEY * private_key,unsigned char ** plaintext)256 int decrypt_rsa_message(const unsigned char *encryptedtext, const int encryptedtext_len, EVP_PKEY *private_key, unsigned char **plaintext) {
257     RSA *rsa = NULL;
258     unsigned char *rsa_buffer = NULL, pad = RSA_PKCS1_PADDING;
259     int plaintext_len, rsa_buffer_len, keysize;
260 
261     rsa = EVP_PKEY_get1_RSA(private_key);
262 
263     keysize = RSA_size(rsa);
264     rsa_buffer  = OPENSSL_malloc(keysize * 2);
265     *plaintext = (unsigned char*)OPENSSL_malloc(keysize);
266 
267     BIO *bioBuff   = BIO_new_mem_buf((void*)encryptedtext, encryptedtext_len);
268     rsa_buffer_len = BIO_read(bioBuff, rsa_buffer, keysize * 2);
269     plaintext_len = RSA_private_decrypt(rsa_buffer_len, rsa_buffer, *plaintext, rsa, pad);
270 
271     RSA_free(rsa);
272     OPENSSL_free(rsa_buffer);
273     BIO_free(bioBuff);
274 
275     if (plaintext_len < 0) {
276       /* We probably shoudln't be printing stuff like this */
277       fprintf(stderr, "%s\n", ERR_error_string(ERR_get_error(), NULL));
278     }
279 
280     return plaintext_len;
281 }
282 
encode_auth_setting(const char * username,const char * password,EVP_PKEY * public_key,char ** authtoken)283 int encode_auth_setting(const char *username, const char *password, EVP_PKEY *public_key, char **authtoken){
284     time_t t = time(NULL);
285     time_t utc_seconds = mktime(localtime(&t));
286 
287     /*
288      * Compute a pessimistic/conservative estimate of storage required.
289      * It's OK to allocate too much storage but too little is bad.
290      */
291     const int text_len = strlen(auth_text_format) + strlen(username) + strlen(password) + 32;
292     char *text = (char *) calloc(text_len, sizeof(char));
293     if (text == NULL) {
294 	return -1;
295     }
296     snprintf(text, text_len, auth_text_format, username, password, (int64_t)utc_seconds);
297 
298     unsigned char *encrypted = NULL;
299     int encrypted_len;
300     encrypted_len = encrypt_rsa_message(text, public_key, &encrypted);
301     free(text);
302     if (encrypted_len < 0) {
303       return -1;
304     }
305     Base64Encode(encrypted, encrypted_len, authtoken);
306     OPENSSL_free(encrypted);
307 
308     return (0); //success
309 }
310 
decode_auth_setting(int enable_debug,const char * authtoken,EVP_PKEY * private_key,char ** username,char ** password,time_t * ts)311 int decode_auth_setting(int enable_debug, const char *authtoken, EVP_PKEY *private_key, char **username, char **password, time_t *ts){
312     unsigned char *encrypted_b64 = NULL;
313     size_t encrypted_len_b64;
314     int64_t utc_seconds;
315     Base64Decode(authtoken, &encrypted_b64, &encrypted_len_b64);
316 
317     unsigned char *plaintext = NULL;
318     int plaintext_len;
319     plaintext_len = decrypt_rsa_message(encrypted_b64, encrypted_len_b64, private_key, &plaintext);
320     free(encrypted_b64);
321     if (plaintext_len < 0) {
322         return -1;
323     }
324     plaintext[plaintext_len] = '\0';
325 
326     char *s_username, *s_password;
327     s_username = (char *) calloc(plaintext_len, sizeof(char));
328     if (s_username == NULL) {
329 	return -1;
330     }
331     s_password = (char *) calloc(plaintext_len, sizeof(char));
332     if (s_password == NULL) {
333 	free(s_username);
334 	return -1;
335     }
336 
337     int rc = sscanf((char *) plaintext, auth_text_format, s_username, s_password, &utc_seconds);
338     if (rc != 3) {
339 	free(s_password);
340 	free(s_username);
341 	return -1;
342     }
343 
344     if (enable_debug) {
345         printf("Auth Token Content:\n%s\n", plaintext);
346         printf("Auth Token Credentials:\n--> %s %s\n", s_username, s_password);
347     }
348     *username = s_username;
349     *password = s_password;
350     *ts = (time_t)utc_seconds;
351     OPENSSL_free(plaintext);
352     return (0);
353 }
354 
355 #endif //HAVE_SSL
356 
iperf_getpass(char ** lineptr,size_t * n,FILE * stream)357 ssize_t iperf_getpass (char **lineptr, size_t *n, FILE *stream) {
358     struct termios old, new;
359     ssize_t nread;
360 
361     /* Turn echoing off and fail if we can't. */
362     if (tcgetattr (fileno (stream), &old) != 0)
363         return -1;
364     new = old;
365     new.c_lflag &= ~ECHO;
366     if (tcsetattr (fileno (stream), TCSAFLUSH, &new) != 0)
367         return -1;
368 
369     /* Read the password. */
370     printf("Password: ");
371     nread = getline (lineptr, n, stream);
372 
373     /* Restore terminal. */
374     (void) tcsetattr (fileno (stream), TCSAFLUSH, &old);
375 
376     //strip the \n or \r\n chars
377     char *buf = *lineptr;
378     int i;
379     for (i = 0; buf[i] != '\0'; i++){
380         if (buf[i] == '\n' || buf[i] == '\r'){
381             buf[i] = '\0';
382             break;
383         }
384     }
385 
386     return nread;
387 }
388 
389 
390