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>