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