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

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

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