File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / iperf / src / iperf_auth.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Sep 27 11:14:54 2023 UTC (9 months ago) by misho
Branches: iperf, MAIN
CVS tags: v3_15, HEAD
Version 3.15

    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: #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:       if (key != NULL) {
  166:           pkey = PEM_read_bio_PUBKEY(key, NULL, NULL, NULL);
  167:           BIO_free(key);
  168:       }
  169:     }
  170:     return (pkey);
  171: }
  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");
  192:       if (key != NULL) {
  193:           pkey = PEM_read_bio_PrivateKey(key, NULL, NULL, NULL);
  194:           BIO_free(key);
  195:       }
  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) {
  251:       /* We probably shouldn't be printing stuff like this */
  252:       fprintf(stderr, "%s\n", ERR_error_string(ERR_get_error(), NULL));
  253:     }
  254: 
  255:     return encryptedtext_len;
  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;
  262: 
  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) {
  278:       /* We probably shouldn't be printing stuff like this */
  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:     }
  298:     snprintf(text, text_len, auth_text_format, username, password, (int64_t)utc_seconds);
  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;
  316:     int64_t utc_seconds;
  317:     Base64Decode(authtoken, &encrypted_b64, &encrypted_len_b64);
  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: 
  339:     int rc = sscanf((char *) plaintext, auth_text_format, s_username, s_password, &utc_seconds);
  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;
  352:     *ts = (time_t)utc_seconds;
  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>