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 #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 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 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 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 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 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 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 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 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 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 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 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 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 shouldn'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 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 shouldn'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 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 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 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