xref: /iperf/src/iperf_auth.c (revision 7cf95d20)
1 /*
2  * iperf, Copyright (c) 2014-2017, 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 #include <stdio.h>
35 #include <termios.h>
36 
37 #if defined(HAVE_SSL)
38 
39 #include <openssl/rsa.h>
40 #include <openssl/bio.h>
41 #include <openssl/pem.h>
42 #include <openssl/sha.h>
43 #include <openssl/buffer.h>
44 
45 void sha256(const char *string, char outputBuffer[65])
46 {
47     unsigned char hash[SHA256_DIGEST_LENGTH];
48     SHA256_CTX sha256;
49     SHA256_Init(&sha256);
50     SHA256_Update(&sha256, string, strlen(string));
51     SHA256_Final(hash, &sha256);
52     int i = 0;
53     for(i = 0; i < SHA256_DIGEST_LENGTH; i++)
54     {
55         sprintf(outputBuffer + (i * 2), "%02x", hash[i]);
56     }
57     outputBuffer[64] = 0;
58 }
59 
60 int check_authentication(const char *username, const char *password, const time_t ts, const char *filename){
61     time_t t = time(NULL);
62     time_t utc_seconds = mktime(localtime(&t));
63     if ( (utc_seconds - ts) < 10 && (utc_seconds - ts) > 0 ){
64         return 1;
65     }
66 
67     char passwordHash[65];
68     char salted[strlen(username) + strlen(password) + 3];
69     sprintf(salted, "{%s}%s", username, password);
70     sha256(&salted[0], passwordHash);
71 
72     char *s_username, *s_password;
73     int i;
74     FILE *ptr_file;
75     char buf[1024];
76 
77     ptr_file =fopen(filename,"r");
78     if (!ptr_file)
79         return 2;
80 
81     while (fgets(buf,1024, ptr_file)){
82         //strip the \n or \r\n chars
83         for (i = 0; buf[i] != '\0'; i++){
84             if (buf[i] == '\n' || buf[i] == '\r'){
85                 buf[i] = '\0';
86                 break;
87             }
88         }
89         //skip empty / not completed / comment lines
90         if (strlen(buf) == 0 || strchr(buf, ',') == NULL || buf[0] == '#'){
91             continue;
92         }
93         s_username = strtok(buf, ",");
94         s_password = strtok(NULL, ",");
95         if (strcmp( username, s_username ) == 0 && strcmp( passwordHash, s_password ) == 0){
96             return 0;
97         }
98     }
99     return 3;
100 }
101 
102 
103 int Base64Encode(unsigned char* buffer, const size_t length, char** b64text) { //Encodes a binary safe base 64 string
104     BIO *bio, *b64;
105     BUF_MEM *bufferPtr;
106 
107     b64 = BIO_new(BIO_f_base64());
108     bio = BIO_new(BIO_s_mem());
109     bio = BIO_push(b64, bio);
110 
111     BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); //Ignore newlines - write everything in one line
112     BIO_write(bio, buffer, length);
113     BIO_flush(bio);
114     BIO_get_mem_ptr(bio, &bufferPtr);
115     BIO_set_close(bio, BIO_NOCLOSE);
116     BIO_free_all(bio);
117 
118     *b64text=(*bufferPtr).data;
119     (*b64text)[(*bufferPtr).length] = '\0';
120     return (0); //success
121 }
122 
123 size_t calcDecodeLength(const char* b64input) { //Calculates the length of a decoded string
124     size_t len = strlen(b64input), padding = 0;
125     if (b64input[len-1] == '=' && b64input[len-2] == '=') //last two chars are =
126         padding = 2;
127     else if (b64input[len-1] == '=') //last char is =
128         padding = 1;
129 
130     return (len*3)/4 - padding;
131 }
132 
133 int Base64Decode(char* b64message, unsigned char** buffer, size_t* length) { //Decodes a base64 encoded string
134     BIO *bio, *b64;
135 
136     int decodeLen = calcDecodeLength(b64message);
137     *buffer = (unsigned char*)malloc(decodeLen + 1);
138     (*buffer)[decodeLen] = '\0';
139 
140     bio = BIO_new_mem_buf(b64message, -1);
141     b64 = BIO_new(BIO_f_base64());
142     bio = BIO_push(b64, bio);
143 
144     BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); //Do not use newlines to flush buffer
145     *length = BIO_read(bio, *buffer, strlen(b64message));
146     assert(*length == decodeLen); //length should equal decodeLen, else something went horribly wrong
147     BIO_free_all(bio);
148 
149     return (0); //success
150 }
151 
152 
153 EVP_PKEY *load_pubkey(const char *file) {
154     BIO *key = NULL;
155     EVP_PKEY *pkey = NULL;
156 
157     key = BIO_new_file(file, "r");
158     pkey = PEM_read_bio_PUBKEY(key, NULL, NULL, NULL);
159 
160     BIO_free(key);
161     return (pkey);
162 }
163 
164 EVP_PKEY *load_key(const char *file) {
165     BIO *key = NULL;
166     EVP_PKEY *pkey = NULL;
167 
168     key = BIO_new_file(file, "r");
169     pkey = PEM_read_bio_PrivateKey(key, NULL, NULL, NULL);
170 
171     BIO_free(key);
172     return (pkey);
173 }
174 
175 
176 int test_load_pubkey(const char *file){
177     EVP_PKEY *key = load_pubkey(file);
178     if (key == NULL){
179         return -1;
180     }
181     EVP_PKEY_free(key);
182     return 0;
183 }
184 
185 int test_load_private_key(const char *file){
186     EVP_PKEY *key = load_key(file);
187     if (key == NULL){
188         return -1;
189     }
190     EVP_PKEY_free(key);
191     return 0;
192 }
193 
194 int encrypt_rsa_message(const char *plaintext, const char *public_keyfile, unsigned char **encryptedtext) {
195     EVP_PKEY *public_key = NULL;
196     RSA *rsa = NULL;
197     unsigned char *rsa_buffer = NULL, pad = RSA_PKCS1_PADDING;
198     int keysize, encryptedtext_len, rsa_buffer_len;
199 
200     public_key = load_pubkey(public_keyfile);
201     rsa = EVP_PKEY_get1_RSA(public_key);
202     EVP_PKEY_free(public_key);
203 
204     keysize = RSA_size(rsa);
205     rsa_buffer  = OPENSSL_malloc(keysize * 2);
206     *encryptedtext = (unsigned char*)OPENSSL_malloc(keysize);
207 
208     BIO *bioBuff   = BIO_new_mem_buf((void*)plaintext, (int)strlen(plaintext));
209     rsa_buffer_len = BIO_read(bioBuff, rsa_buffer, keysize * 2);
210     encryptedtext_len = RSA_public_encrypt(rsa_buffer_len, rsa_buffer, *encryptedtext, rsa, pad);
211 
212     RSA_free(rsa);
213     OPENSSL_free(rsa_buffer);
214     OPENSSL_free(bioBuff);
215 
216     return encryptedtext_len;
217 }
218 
219 int decrypt_rsa_message(const unsigned char *encryptedtext, const int encryptedtext_len, const char *private_keyfile, unsigned char **plaintext) {
220     EVP_PKEY *private_key = NULL;
221     RSA *rsa = NULL;
222     unsigned char *rsa_buffer = NULL, pad = RSA_PKCS1_PADDING;
223     int plaintext_len, rsa_buffer_len, keysize;
224 
225     private_key = load_key(private_keyfile);
226     rsa = EVP_PKEY_get1_RSA(private_key);
227     EVP_PKEY_free(private_key);
228 
229     keysize = RSA_size(rsa);
230     rsa_buffer  = OPENSSL_malloc(keysize * 2);
231     *plaintext = (unsigned char*)OPENSSL_malloc(keysize);
232 
233     BIO *bioBuff   = BIO_new_mem_buf((void*)encryptedtext, encryptedtext_len);
234     rsa_buffer_len = BIO_read(bioBuff, rsa_buffer, keysize * 2);
235     plaintext_len = RSA_private_decrypt(rsa_buffer_len, rsa_buffer, *plaintext, rsa, pad);
236 
237     RSA_free(rsa);
238     OPENSSL_free(rsa_buffer);
239     OPENSSL_free(bioBuff);
240 
241     return plaintext_len;
242 }
243 
244 int encode_auth_setting(const char *username, const char *password, const char *public_keyfile, char **authtoken){
245     time_t t = time(NULL);
246     time_t utc_seconds = mktime(localtime(&t));
247     char text[150];
248     sprintf (text, "user: %s\npwd:  %s\nts:   %ld", username, password, utc_seconds);
249     unsigned char *encrypted = NULL;
250     int encrypted_len;
251     encrypted_len = encrypt_rsa_message(text, public_keyfile, &encrypted);
252     Base64Encode(encrypted, encrypted_len, authtoken);
253     return (0); //success
254 }
255 
256 int decode_auth_setting(int enable_debug, char *authtoken, const char *private_keyfile, char **username, char **password, time_t *ts){
257     unsigned char *encrypted_b64 = NULL;
258     size_t encrypted_len_b64;
259     Base64Decode(authtoken, &encrypted_b64, &encrypted_len_b64);
260 
261     unsigned char *plaintext = NULL;
262     int plaintext_len;
263     plaintext_len = decrypt_rsa_message(encrypted_b64, encrypted_len_b64, private_keyfile, &plaintext);
264     plaintext[plaintext_len] = '\0';
265 
266     char s_username[20], s_password[20];
267     sscanf ((char *)plaintext,"user: %s\npwd:  %s\nts:   %ld", s_username, s_password, ts);
268     if (enable_debug) {
269         printf("Auth Token Content:\n%s\n", plaintext);
270         printf("Auth Token Credentials:\n--> %s %s\n", s_username, s_password);
271     }
272     *username = (char *) calloc(21, sizeof(char));
273     *password = (char *) calloc(21, sizeof(char));
274     strncpy(*username, s_username, 20);
275     strncpy(*password, s_password, 20);
276     return (0);
277 }
278 
279 #endif //HAVE_SSL
280 
281 ssize_t iperf_getpass (char **lineptr, size_t *n, FILE *stream) {
282     struct termios old, new;
283     ssize_t nread;
284 
285     /* Turn echoing off and fail if we can't. */
286     if (tcgetattr (fileno (stream), &old) != 0)
287         return -1;
288     new = old;
289     new.c_lflag &= ~ECHO;
290     if (tcsetattr (fileno (stream), TCSAFLUSH, &new) != 0)
291         return -1;
292 
293     /* Read the password. */
294     printf("Password: ");
295     nread = getline (lineptr, n, stream);
296 
297     /* Restore terminal. */
298     (void) tcsetattr (fileno (stream), TCSAFLUSH, &old);
299 
300     //strip the \n or \r\n chars
301     char *buf = *lineptr;
302     int i;
303     for (i = 0; buf[i] != '\0'; i++){
304         if (buf[i] == '\n' || buf[i] == '\r'){
305             buf[i] = '\0';
306             break;
307         }
308     }
309 
310     return nread;
311 }
312 
313 
314