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>