Annotation of embedaddon/iperf/src/iperf_auth.c, revision 1.1.1.2

1.1       misho       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>
1.1.1.2 ! misho      38: #include <inttypes.h>
        !            39: #include <stdint.h>
1.1       misho      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: 
1.1.1.2 ! misho      50: const char *auth_text_format = "user: %s\npwd:  %s\nts:   %"PRId64;
1.1       misho      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: 
1.1.1.2 ! misho      67: int check_authentication(const char *username, const char *password, const time_t ts, const char *filename, int skew_threshold){
1.1       misho      68:     time_t t = time(NULL);
                     69:     time_t utc_seconds = mktime(localtime(&t));
1.1.1.2 ! misho      70:     if ( (utc_seconds - ts) > skew_threshold || (utc_seconds - ts) < -skew_threshold ) {
1.1       misho      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");
1.1.1.2 ! misho     165:       if (key != NULL) {
        !           166:           pkey = PEM_read_bio_PUBKEY(key, NULL, NULL, NULL);
        !           167:           BIO_free(key);
        !           168:       }
1.1       misho     169:     }
                    170:     return (pkey);
1.1.1.2 ! misho     171: }
1.1       misho     172: 
                    173: EVP_PKEY *load_pubkey_from_base64(const char *buffer) {
                    174:     unsigned char *key = NULL;
                    175:     size_t key_len;
                    176:     Base64Decode(buffer, &key, &key_len);
                    177: 
                    178:     BIO* bio = BIO_new(BIO_s_mem());
                    179:     BIO_write(bio, key, key_len);
                    180:     free(key);
                    181:     EVP_PKEY *pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
                    182:     BIO_free(bio);
                    183:     return (pkey);
                    184: }
                    185: 
                    186: EVP_PKEY *load_privkey_from_file(const char *file) {
                    187:     BIO *key = NULL;
                    188:     EVP_PKEY *pkey = NULL;
                    189: 
                    190:     if (file) {
                    191:       key = BIO_new_file(file, "r");
1.1.1.2 ! misho     192:       if (key != NULL) {
        !           193:           pkey = PEM_read_bio_PrivateKey(key, NULL, NULL, NULL);
        !           194:           BIO_free(key);
        !           195:       }
1.1       misho     196:     }
                    197:     return (pkey);
                    198: }
                    199: 
                    200: EVP_PKEY *load_privkey_from_base64(const char *buffer) {
                    201:     unsigned char *key = NULL;
                    202:     size_t key_len;
                    203:     Base64Decode(buffer, &key, &key_len);
                    204: 
                    205:     BIO* bio = BIO_new(BIO_s_mem());
                    206:     BIO_write(bio, key, key_len);
                    207:     free(key);
                    208:     EVP_PKEY *pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
                    209:     BIO_free(bio);
                    210:     return (pkey);
                    211: }
                    212: 
                    213: int test_load_pubkey_from_file(const char *file){
                    214:     EVP_PKEY *key = load_pubkey_from_file(file);
                    215:     if (key == NULL){
                    216:         return -1;
                    217:     }
                    218:     EVP_PKEY_free(key);
                    219:     return 0;
                    220: }
                    221: 
                    222: int test_load_private_key_from_file(const char *file){
                    223:     EVP_PKEY *key = load_privkey_from_file(file);
                    224:     if (key == NULL){
                    225:         return -1;
                    226:     }
                    227:     EVP_PKEY_free(key);
                    228:     return 0;
                    229: }
                    230: 
                    231: int encrypt_rsa_message(const char *plaintext, EVP_PKEY *public_key, unsigned char **encryptedtext) {
                    232:     RSA *rsa = NULL;
                    233:     unsigned char *rsa_buffer = NULL, pad = RSA_PKCS1_PADDING;
                    234:     int keysize, encryptedtext_len, rsa_buffer_len;
                    235: 
                    236:     rsa = EVP_PKEY_get1_RSA(public_key);
                    237:     keysize = RSA_size(rsa);
                    238: 
                    239:     rsa_buffer  = OPENSSL_malloc(keysize * 2);
                    240:     *encryptedtext = (unsigned char*)OPENSSL_malloc(keysize);
                    241: 
                    242:     BIO *bioBuff   = BIO_new_mem_buf((void*)plaintext, (int)strlen(plaintext));
                    243:     rsa_buffer_len = BIO_read(bioBuff, rsa_buffer, keysize * 2);
                    244:     encryptedtext_len = RSA_public_encrypt(rsa_buffer_len, rsa_buffer, *encryptedtext, rsa, pad);
                    245: 
                    246:     RSA_free(rsa);
                    247:     OPENSSL_free(rsa_buffer);
                    248:     BIO_free(bioBuff);
                    249: 
                    250:     if (encryptedtext_len < 0) {
1.1.1.2 ! misho     251:       /* We probably shouldn't be printing stuff like this */
1.1       misho     252:       fprintf(stderr, "%s\n", ERR_error_string(ERR_get_error(), NULL));
                    253:     }
                    254: 
1.1.1.2 ! misho     255:     return encryptedtext_len;
1.1       misho     256: }
                    257: 
                    258: int decrypt_rsa_message(const unsigned char *encryptedtext, const int encryptedtext_len, EVP_PKEY *private_key, unsigned char **plaintext) {
                    259:     RSA *rsa = NULL;
                    260:     unsigned char *rsa_buffer = NULL, pad = RSA_PKCS1_PADDING;
                    261:     int plaintext_len, rsa_buffer_len, keysize;
1.1.1.2 ! misho     262: 
1.1       misho     263:     rsa = EVP_PKEY_get1_RSA(private_key);
                    264: 
                    265:     keysize = RSA_size(rsa);
                    266:     rsa_buffer  = OPENSSL_malloc(keysize * 2);
                    267:     *plaintext = (unsigned char*)OPENSSL_malloc(keysize);
                    268: 
                    269:     BIO *bioBuff   = BIO_new_mem_buf((void*)encryptedtext, encryptedtext_len);
                    270:     rsa_buffer_len = BIO_read(bioBuff, rsa_buffer, keysize * 2);
                    271:     plaintext_len = RSA_private_decrypt(rsa_buffer_len, rsa_buffer, *plaintext, rsa, pad);
                    272: 
                    273:     RSA_free(rsa);
                    274:     OPENSSL_free(rsa_buffer);
                    275:     BIO_free(bioBuff);
                    276: 
                    277:     if (plaintext_len < 0) {
1.1.1.2 ! misho     278:       /* We probably shouldn't be printing stuff like this */
1.1       misho     279:       fprintf(stderr, "%s\n", ERR_error_string(ERR_get_error(), NULL));
                    280:     }
                    281: 
                    282:     return plaintext_len;
                    283: }
                    284: 
                    285: int encode_auth_setting(const char *username, const char *password, EVP_PKEY *public_key, char **authtoken){
                    286:     time_t t = time(NULL);
                    287:     time_t utc_seconds = mktime(localtime(&t));
                    288: 
                    289:     /*
                    290:      * Compute a pessimistic/conservative estimate of storage required.
                    291:      * It's OK to allocate too much storage but too little is bad.
                    292:      */
                    293:     const int text_len = strlen(auth_text_format) + strlen(username) + strlen(password) + 32;
                    294:     char *text = (char *) calloc(text_len, sizeof(char));
                    295:     if (text == NULL) {
                    296:        return -1;
                    297:     }
1.1.1.2 ! misho     298:     snprintf(text, text_len, auth_text_format, username, password, (int64_t)utc_seconds);
1.1       misho     299: 
                    300:     unsigned char *encrypted = NULL;
                    301:     int encrypted_len;
                    302:     encrypted_len = encrypt_rsa_message(text, public_key, &encrypted);
                    303:     free(text);
                    304:     if (encrypted_len < 0) {
                    305:       return -1;
                    306:     }
                    307:     Base64Encode(encrypted, encrypted_len, authtoken);
                    308:     OPENSSL_free(encrypted);
                    309: 
                    310:     return (0); //success
                    311: }
                    312: 
                    313: int decode_auth_setting(int enable_debug, const char *authtoken, EVP_PKEY *private_key, char **username, char **password, time_t *ts){
                    314:     unsigned char *encrypted_b64 = NULL;
                    315:     size_t encrypted_len_b64;
1.1.1.2 ! misho     316:     int64_t utc_seconds;
        !           317:     Base64Decode(authtoken, &encrypted_b64, &encrypted_len_b64);
1.1       misho     318: 
                    319:     unsigned char *plaintext = NULL;
                    320:     int plaintext_len;
                    321:     plaintext_len = decrypt_rsa_message(encrypted_b64, encrypted_len_b64, private_key, &plaintext);
                    322:     free(encrypted_b64);
                    323:     if (plaintext_len < 0) {
                    324:         return -1;
                    325:     }
                    326:     plaintext[plaintext_len] = '\0';
                    327: 
                    328:     char *s_username, *s_password;
                    329:     s_username = (char *) calloc(plaintext_len, sizeof(char));
                    330:     if (s_username == NULL) {
                    331:        return -1;
                    332:     }
                    333:     s_password = (char *) calloc(plaintext_len, sizeof(char));
                    334:     if (s_password == NULL) {
                    335:        free(s_username);
                    336:        return -1;
                    337:     }
                    338: 
1.1.1.2 ! misho     339:     int rc = sscanf((char *) plaintext, auth_text_format, s_username, s_password, &utc_seconds);
1.1       misho     340:     if (rc != 3) {
                    341:        free(s_password);
                    342:        free(s_username);
                    343:        return -1;
                    344:     }
                    345: 
                    346:     if (enable_debug) {
                    347:         printf("Auth Token Content:\n%s\n", plaintext);
                    348:         printf("Auth Token Credentials:\n--> %s %s\n", s_username, s_password);
                    349:     }
                    350:     *username = s_username;
                    351:     *password = s_password;
1.1.1.2 ! misho     352:     *ts = (time_t)utc_seconds;
1.1       misho     353:     OPENSSL_free(plaintext);
                    354:     return (0);
                    355: }
                    356: 
                    357: #endif //HAVE_SSL
                    358: 
                    359: ssize_t iperf_getpass (char **lineptr, size_t *n, FILE *stream) {
                    360:     struct termios old, new;
                    361:     ssize_t nread;
                    362: 
                    363:     /* Turn echoing off and fail if we can't. */
                    364:     if (tcgetattr (fileno (stream), &old) != 0)
                    365:         return -1;
                    366:     new = old;
                    367:     new.c_lflag &= ~ECHO;
                    368:     if (tcsetattr (fileno (stream), TCSAFLUSH, &new) != 0)
                    369:         return -1;
                    370: 
                    371:     /* Read the password. */
                    372:     printf("Password: ");
                    373:     nread = getline (lineptr, n, stream);
                    374: 
                    375:     /* Restore terminal. */
                    376:     (void) tcsetattr (fileno (stream), TCSAFLUSH, &old);
                    377: 
                    378:     //strip the \n or \r\n chars
                    379:     char *buf = *lineptr;
                    380:     int i;
                    381:     for (i = 0; buf[i] != '\0'; i++){
                    382:         if (buf[i] == '\n' || buf[i] == '\r'){
                    383:             buf[i] = '\0';
                    384:             break;
                    385:         }
                    386:     }
                    387: 
                    388:     return nread;
                    389: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>