Home | History | Annotate | Download | only in src
      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 TTD (at) 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 
     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             return 0;
     99         }
    100     }
    101     fclose(ptr_file);
    102     return 3;
    103 }
    104 
    105 
    106 int Base64Encode(const unsigned char* buffer, const size_t length, char** b64text) { //Encodes a binary safe base 64 string
    107     BIO *bio, *b64;
    108     BUF_MEM *bufferPtr;
    109 
    110     b64 = BIO_new(BIO_f_base64());
    111     bio = BIO_new(BIO_s_mem());
    112     bio = BIO_push(b64, bio);
    113 
    114     BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); //Ignore newlines - write everything in one line
    115     BIO_write(bio, buffer, length);
    116     BIO_flush(bio);
    117     BIO_get_mem_ptr(bio, &bufferPtr);
    118     BIO_set_close(bio, BIO_NOCLOSE);
    119     BIO_free_all(bio);
    120 
    121     *b64text=(*bufferPtr).data;
    122     (*b64text)[(*bufferPtr).length] = '\0';
    123     return (0); //success
    124 }
    125 
    126 size_t calcDecodeLength(const char* b64input) { //Calculates the length of a decoded string
    127     size_t len = strlen(b64input), padding = 0;
    128     if (b64input[len-1] == '=' && b64input[len-2] == '=') //last two chars are =
    129         padding = 2;
    130     else if (b64input[len-1] == '=') //last char is =
    131         padding = 1;
    132 
    133     return (len*3)/4 - padding;
    134 }
    135 
    136 int Base64Decode(const char* b64message, unsigned char** buffer, size_t* length) { //Decodes a base64 encoded string
    137     BIO *bio, *b64;
    138 
    139     int decodeLen = calcDecodeLength(b64message);
    140     *buffer = (unsigned char*)malloc(decodeLen + 1);
    141     (*buffer)[decodeLen] = '\0';
    142 
    143     bio = BIO_new_mem_buf(b64message, -1);
    144     b64 = BIO_new(BIO_f_base64());
    145     bio = BIO_push(b64, bio);
    146 
    147     BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); //Do not use newlines to flush buffer
    148     *length = BIO_read(bio, *buffer, strlen(b64message));
    149     assert(*length == decodeLen); //length should equal decodeLen, else something went horribly wrong
    150     BIO_free_all(bio);
    151 
    152     return (0); //success
    153 }
    154 
    155 
    156 EVP_PKEY *load_pubkey_from_file(const char *file) {
    157     BIO *key = NULL;
    158     EVP_PKEY *pkey = NULL;
    159 
    160     key = BIO_new_file(file, "r");
    161     pkey = PEM_read_bio_PUBKEY(key, NULL, NULL, NULL);
    162 
    163     BIO_free(key);
    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     return (pkey);
    176 }
    177 
    178 EVP_PKEY *load_privkey_from_file(const char *file) {
    179     BIO *key = NULL;
    180     EVP_PKEY *pkey = NULL;
    181 
    182     key = BIO_new_file(file, "r");
    183     pkey = PEM_read_bio_PrivateKey(key, NULL, NULL, NULL);
    184 
    185     BIO_free(key);
    186     return (pkey);
    187 }
    188 
    189 
    190 int test_load_pubkey_from_file(const char *file){
    191     EVP_PKEY *key = load_pubkey_from_file(file);
    192     if (key == NULL){
    193         return -1;
    194     }
    195     EVP_PKEY_free(key);
    196     return 0;
    197 }
    198 
    199 int test_load_private_key_from_file(const char *file){
    200     EVP_PKEY *key = load_privkey_from_file(file);
    201     if (key == NULL){
    202         return -1;
    203     }
    204     EVP_PKEY_free(key);
    205     return 0;
    206 }
    207 
    208 int encrypt_rsa_message(const char *plaintext, EVP_PKEY *public_key, unsigned char **encryptedtext) {
    209     RSA *rsa = NULL;
    210     unsigned char *rsa_buffer = NULL, pad = RSA_PKCS1_PADDING;
    211     int keysize, encryptedtext_len, rsa_buffer_len;
    212 
    213     rsa = EVP_PKEY_get1_RSA(public_key);
    214     keysize = RSA_size(rsa);
    215 
    216     rsa_buffer  = OPENSSL_malloc(keysize * 2);
    217     *encryptedtext = (unsigned char*)OPENSSL_malloc(keysize);
    218 
    219     BIO *bioBuff   = BIO_new_mem_buf((void*)plaintext, (int)strlen(plaintext));
    220     rsa_buffer_len = BIO_read(bioBuff, rsa_buffer, keysize * 2);
    221     encryptedtext_len = RSA_public_encrypt(rsa_buffer_len, rsa_buffer, *encryptedtext, rsa, pad);
    222 
    223     RSA_free(rsa);
    224     OPENSSL_free(rsa_buffer);
    225     OPENSSL_free(bioBuff);
    226 
    227     return encryptedtext_len;
    228 }
    229 
    230 int decrypt_rsa_message(const unsigned char *encryptedtext, const int encryptedtext_len, EVP_PKEY *private_key, unsigned char **plaintext) {
    231     RSA *rsa = NULL;
    232     unsigned char *rsa_buffer = NULL, pad = RSA_PKCS1_PADDING;
    233     int plaintext_len, rsa_buffer_len, keysize;
    234 
    235     rsa = EVP_PKEY_get1_RSA(private_key);
    236 
    237     keysize = RSA_size(rsa);
    238     rsa_buffer  = OPENSSL_malloc(keysize * 2);
    239     *plaintext = (unsigned char*)OPENSSL_malloc(keysize);
    240 
    241     BIO *bioBuff   = BIO_new_mem_buf((void*)encryptedtext, encryptedtext_len);
    242     rsa_buffer_len = BIO_read(bioBuff, rsa_buffer, keysize * 2);
    243     plaintext_len = RSA_private_decrypt(rsa_buffer_len, rsa_buffer, *plaintext, rsa, pad);
    244 
    245     RSA_free(rsa);
    246     OPENSSL_free(rsa_buffer);
    247     OPENSSL_free(bioBuff);
    248 
    249     return plaintext_len;
    250 }
    251 
    252 int encode_auth_setting(const char *username, const char *password, EVP_PKEY *public_key, char **authtoken){
    253     time_t t = time(NULL);
    254     time_t utc_seconds = mktime(localtime(&t));
    255     char text[150];
    256     sprintf (text, "user: %s\npwd:  %s\nts:   %ld", username, password, utc_seconds);
    257     unsigned char *encrypted = NULL;
    258     int encrypted_len;
    259     encrypted_len = encrypt_rsa_message(text, public_key, &encrypted);
    260     Base64Encode(encrypted, encrypted_len, authtoken);
    261     return (0); //success
    262 }
    263 
    264 int decode_auth_setting(int enable_debug, char *authtoken, EVP_PKEY *private_key, char **username, char **password, time_t *ts){
    265     unsigned char *encrypted_b64 = NULL;
    266     size_t encrypted_len_b64;
    267     Base64Decode(authtoken, &encrypted_b64, &encrypted_len_b64);
    268 
    269     unsigned char *plaintext = NULL;
    270     int plaintext_len;
    271     plaintext_len = decrypt_rsa_message(encrypted_b64, encrypted_len_b64, private_key, &plaintext);
    272     plaintext[plaintext_len] = '\0';
    273 
    274     char s_username[20], s_password[20];
    275     sscanf ((char *)plaintext,"user: %s\npwd:  %s\nts:   %ld", s_username, s_password, ts);
    276     if (enable_debug) {
    277         printf("Auth Token Content:\n%s\n", plaintext);
    278         printf("Auth Token Credentials:\n--> %s %s\n", s_username, s_password);
    279     }
    280     *username = (char *) calloc(21, sizeof(char));
    281     *password = (char *) calloc(21, sizeof(char));
    282     strncpy(*username, s_username, 20);
    283     strncpy(*password, s_password, 20);
    284     return (0);
    285 }
    286 
    287 #endif //HAVE_SSL
    288 
    289 ssize_t iperf_getpass (char **lineptr, size_t *n, FILE *stream) {
    290     struct termios old, new;
    291     ssize_t nread;
    292 
    293     /* Turn echoing off and fail if we can't. */
    294     if (tcgetattr (fileno (stream), &old) != 0)
    295         return -1;
    296     new = old;
    297     new.c_lflag &= ~ECHO;
    298     if (tcsetattr (fileno (stream), TCSAFLUSH, &new) != 0)
    299         return -1;
    300 
    301     /* Read the password. */
    302     printf("Password: ");
    303     nread = getline (lineptr, n, stream);
    304 
    305     /* Restore terminal. */
    306     (void) tcsetattr (fileno (stream), TCSAFLUSH, &old);
    307 
    308     //strip the \n or \r\n chars
    309     char *buf = *lineptr;
    310     int i;
    311     for (i = 0; buf[i] != '\0'; i++){
    312         if (buf[i] == '\n' || buf[i] == '\r'){
    313             buf[i] = '\0';
    314             break;
    315         }
    316     }
    317 
    318     return nread;
    319 }
    320 
    321 
    322