2022-03-08 19:46:00 +00:00
|
|
|
/* Copyright 2019-2021 Lenovo */
|
|
|
|
|
|
|
|
#include "sha-256.h"
|
2019-08-08 20:14:05 +00:00
|
|
|
#include <arpa/inet.h>
|
|
|
|
#include <crypt.h>
|
|
|
|
#include <net/if.h>
|
2019-08-09 20:43:48 +00:00
|
|
|
#include <netdb.h>
|
2019-08-08 20:14:05 +00:00
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <sys/types.h>
|
2019-08-09 20:43:48 +00:00
|
|
|
#include <sys/time.h>
|
2019-08-08 20:14:05 +00:00
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#define MAXPACKET 1024
|
|
|
|
|
2023-01-19 19:53:35 +00:00
|
|
|
static const char cryptalpha[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789./";
|
2023-03-13 20:20:17 +00:00
|
|
|
static const char b64alpha[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
2019-08-08 20:14:05 +00:00
|
|
|
|
2019-08-09 20:43:48 +00:00
|
|
|
unsigned char* genpasswd(int len) {
|
2019-08-08 20:14:05 +00:00
|
|
|
unsigned char * passwd;
|
2020-05-04 14:22:04 +00:00
|
|
|
int urandom, ret;
|
2019-08-09 20:43:48 +00:00
|
|
|
passwd = calloc(len + 1, sizeof(char));
|
2019-08-08 20:14:05 +00:00
|
|
|
urandom = open("/dev/urandom", O_RDONLY);
|
2022-02-17 22:05:00 +00:00
|
|
|
if (urandom < 0) {
|
|
|
|
fprintf(stderr, "Failed reading /dev/urandom\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
2020-05-04 14:22:04 +00:00
|
|
|
ret = read(urandom, passwd, len);
|
2019-08-08 20:14:05 +00:00
|
|
|
close(urandom);
|
2019-08-09 20:43:48 +00:00
|
|
|
for (urandom = 0; urandom < len; urandom++) {
|
|
|
|
passwd[urandom] = cryptalpha[passwd[urandom] >> 2];
|
2019-08-08 20:14:05 +00:00
|
|
|
}
|
2022-02-17 22:05:00 +00:00
|
|
|
passwd[len] = 0; // Should be redundant with calloc, but be explicit
|
2019-08-08 20:14:05 +00:00
|
|
|
return passwd;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2022-03-10 14:00:54 +00:00
|
|
|
char * b64e(uint8_t * data, uint32_t datalen) {
|
|
|
|
uint8_t * currptr;
|
|
|
|
uint8_t * currout;
|
|
|
|
uint8_t currchunk[4];
|
|
|
|
uint8_t * retval;
|
|
|
|
uint32_t neededlen;
|
|
|
|
int32_t remaining = datalen;
|
|
|
|
neededlen = (datalen - 1) / 3 * 4 + 4;
|
|
|
|
retval = malloc(neededlen + 1);
|
|
|
|
currout = retval;
|
|
|
|
currptr = data;
|
|
|
|
currchunk[3] = 0;
|
|
|
|
while (remaining > 0) {
|
|
|
|
currchunk[0] = currptr[0];
|
|
|
|
currchunk[1] = remaining > 1 ? currptr[1] : 0;
|
|
|
|
currchunk[2] = remaining > 2 ? currptr[2] : 0;
|
|
|
|
currptr += 3;
|
2023-03-13 20:20:17 +00:00
|
|
|
currout[0] = b64alpha[currchunk[0] >> 2];
|
|
|
|
currout[1] = b64alpha[(currchunk[0] << 4 | currchunk[1] >> 4) & 0x3f];
|
|
|
|
currout[2] = remaining > 1 ? b64alpha[(currchunk[1] << 2 | currchunk[2] >> 6) & 0x3f] : '=';
|
|
|
|
currout[3] = remaining > 2 ? b64alpha[currchunk[2] & 0x3f] : '=';
|
2022-03-10 14:00:54 +00:00
|
|
|
remaining -= 3;
|
|
|
|
currout += 4;
|
|
|
|
}
|
|
|
|
retval[neededlen] = 0;
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2022-03-09 18:36:47 +00:00
|
|
|
int getpasshmac(int argc, char* argv[]) {
|
|
|
|
FILE *outfile;
|
|
|
|
uint8_t *passwd;
|
|
|
|
uint8_t *buffer;
|
|
|
|
uint8_t *tmps;
|
|
|
|
uint8_t *cryptpass;
|
|
|
|
uint8_t hmac[32];
|
2022-03-10 14:00:54 +00:00
|
|
|
uint8_t *hmac64;
|
2022-03-09 18:36:47 +00:00
|
|
|
uint8_t hmackey[64];
|
|
|
|
int hmackeysize;
|
|
|
|
if (argc < 5) {
|
|
|
|
fprintf(stderr, "Usage: %s passfile cryptfile hmacfile hmackey\n", argv[0]);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
outfile = fopen(argv[4], "r");
|
|
|
|
hmackeysize = fread(hmackey, 1, 64, outfile);
|
|
|
|
fclose(outfile);
|
|
|
|
passwd = genpasswd(48);
|
|
|
|
outfile = fopen(argv[1], "w");
|
|
|
|
buffer = malloc(20);
|
|
|
|
tmps = genpasswd(16);
|
|
|
|
memcpy(buffer, "$5$", 3);
|
|
|
|
memcpy(buffer + 3, tmps, 16);
|
Tweak various issues for static analysis.
For autocons, though it's copying from a static source, use strncpy anyway,
despite the length being hardcoded already. This makes static analysis happier.
Terminate the buff with a NULL. This is superfluous as the strcpies that preceed
are guaranteed to null terminate, or exit the program.
In clortho, free(tmps), which is a valid leak, though clortho isn't long running.
Also, explicitly return 0, which is ultimately returned by main().
Static analysis could not figure out that padneeded implies that keylen is short of
chunk size, so change the check to be expressly the scenario that static analysis
was worried about directly, rather than indirectly.
Hint to static analysis that we don't care about the time as a time value by masking the
lower 32 bit explicitly. This was already happening, but static analysis was afraid
that we wanted this as time instead of just some mutating value.
2022-12-06 20:35:49 +00:00
|
|
|
free(tmps);
|
2022-03-09 18:36:47 +00:00
|
|
|
buffer[19] = 0;
|
|
|
|
fwrite(passwd, 1, 48, outfile);
|
|
|
|
fclose(outfile);
|
|
|
|
cryptpass = crypt(passwd, buffer);
|
|
|
|
outfile = fopen(argv[2], "w");
|
|
|
|
fwrite(cryptpass, 1, strlen(cryptpass), outfile);
|
|
|
|
fclose(outfile);
|
|
|
|
hmac_sha256(hmac, cryptpass, strlen(cryptpass), hmackey, hmackeysize);
|
2022-03-10 14:15:26 +00:00
|
|
|
hmac64 = b64e(hmac, 32);
|
2022-03-09 18:36:47 +00:00
|
|
|
outfile = fopen(argv[3], "w");
|
2022-03-10 14:00:54 +00:00
|
|
|
fwrite(hmac64, 1, strlen(hmac64), outfile);
|
2022-03-09 18:36:47 +00:00
|
|
|
fclose(outfile);
|
2022-03-10 14:00:54 +00:00
|
|
|
free(hmac64);
|
2022-03-09 18:36:47 +00:00
|
|
|
free(passwd);
|
|
|
|
free(buffer);
|
Tweak various issues for static analysis.
For autocons, though it's copying from a static source, use strncpy anyway,
despite the length being hardcoded already. This makes static analysis happier.
Terminate the buff with a NULL. This is superfluous as the strcpies that preceed
are guaranteed to null terminate, or exit the program.
In clortho, free(tmps), which is a valid leak, though clortho isn't long running.
Also, explicitly return 0, which is ultimately returned by main().
Static analysis could not figure out that padneeded implies that keylen is short of
chunk size, so change the check to be expressly the scenario that static analysis
was worried about directly, rather than indirectly.
Hint to static analysis that we don't care about the time as a time value by masking the
lower 32 bit explicitly. This was already happening, but static analysis was afraid
that we wanted this as time instead of just some mutating value.
2022-12-06 20:35:49 +00:00
|
|
|
return 0;
|
2022-03-09 18:36:47 +00:00
|
|
|
}
|
2019-08-08 20:14:05 +00:00
|
|
|
|
|
|
|
int main(int argc, char* argv[]) {
|
2020-05-04 14:22:04 +00:00
|
|
|
int sock, ret;
|
2020-05-04 21:27:22 +00:00
|
|
|
char slen;
|
2020-11-06 15:00:36 +00:00
|
|
|
unsigned char currtype;
|
|
|
|
size_t currlen;
|
2019-08-08 20:14:05 +00:00
|
|
|
unsigned char* passwd;
|
2019-08-09 20:43:48 +00:00
|
|
|
unsigned char* cryptedpass;
|
2019-08-08 20:14:05 +00:00
|
|
|
unsigned char* macaddr;
|
2019-08-09 20:43:48 +00:00
|
|
|
struct timeval timeout;
|
|
|
|
struct addrinfo hints;
|
|
|
|
struct addrinfo *addrs;
|
|
|
|
struct addrinfo *curr;
|
|
|
|
struct sockaddr_in net4bind;
|
2020-03-02 21:06:07 +00:00
|
|
|
struct sockaddr_in6 net6bind;
|
2022-03-08 19:46:00 +00:00
|
|
|
FILE *hmackeyfile;
|
|
|
|
uint8_t hmackey[64];
|
|
|
|
uint8_t hmac[32];
|
|
|
|
int hmackeysize = 0;
|
2019-08-08 20:14:05 +00:00
|
|
|
unsigned char buffer[MAXPACKET];
|
2019-08-09 20:43:48 +00:00
|
|
|
memset(&hints, 0, sizeof(struct addrinfo));
|
|
|
|
memset(&net4bind, 0, sizeof(struct sockaddr_in));
|
2020-03-02 21:06:07 +00:00
|
|
|
memset(&net6bind, 0, sizeof(struct sockaddr_in6));
|
2019-08-09 20:43:48 +00:00
|
|
|
memset(&buffer, 0, MAXPACKET);
|
|
|
|
memset(&timeout, 0, sizeof(struct timeval));
|
2022-03-09 18:36:47 +00:00
|
|
|
if (strstr(argv[0], "genpasshmac") != NULL) {
|
|
|
|
return getpasshmac(argc, argv);
|
|
|
|
}
|
2019-08-09 20:43:48 +00:00
|
|
|
timeout.tv_sec = 10;
|
|
|
|
net4bind.sin_port = htons(302);
|
2020-06-19 14:24:51 +00:00
|
|
|
net4bind.sin_family = AF_INET;
|
2020-03-02 21:06:07 +00:00
|
|
|
net6bind.sin6_port = htons(302);
|
|
|
|
net6bind.sin6_family = AF_INET6;
|
2019-08-09 20:43:48 +00:00
|
|
|
hints.ai_socktype = SOCK_STREAM;
|
|
|
|
hints.ai_protocol = IPPROTO_TCP;
|
2019-08-08 20:14:05 +00:00
|
|
|
|
2019-08-09 20:43:48 +00:00
|
|
|
passwd = genpasswd(32);
|
|
|
|
memset(buffer, 0, MAXPACKET);
|
|
|
|
strncpy(buffer, "$5$", 3);
|
|
|
|
cryptedpass = genpasswd(8);
|
|
|
|
strncpy(buffer + 3, cryptedpass, 8);
|
|
|
|
free(cryptedpass);
|
|
|
|
cryptedpass = crypt(passwd, buffer);
|
2020-02-27 21:36:16 +00:00
|
|
|
if (argc < 3) {
|
2019-08-09 20:43:48 +00:00
|
|
|
fprintf(stderr, "Missing node name and manager\n");
|
2019-08-08 20:14:05 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
2022-03-08 19:46:00 +00:00
|
|
|
if (argc == 4) {
|
|
|
|
hmackeyfile = fopen(argv[3], "r");
|
|
|
|
hmackeysize = fread(hmackey, 1, 64, hmackeyfile);
|
|
|
|
fclose(hmackeyfile);
|
|
|
|
hmac_sha256(hmac, cryptedpass, strlen(cryptedpass), hmackey, hmackeysize);
|
|
|
|
}
|
2020-02-27 21:36:16 +00:00
|
|
|
sock = getaddrinfo(argv[2], "13001", &hints, &addrs);
|
2019-08-09 20:43:48 +00:00
|
|
|
if (sock != 0) {
|
|
|
|
fprintf(stderr, "Error trying to resolve %s\n", argv[2]);
|
2019-08-08 20:14:05 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
2019-08-09 20:43:48 +00:00
|
|
|
for (curr = addrs; curr != NULL; curr = curr->ai_next) {
|
|
|
|
sock = socket(curr->ai_family, curr->ai_socktype, curr->ai_protocol);
|
|
|
|
if (sock < 0) continue;
|
2022-02-17 22:05:00 +00:00
|
|
|
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)) < 0) {
|
|
|
|
fprintf(stderr, "Failed setting reusaddr\n");
|
|
|
|
}
|
2019-08-09 20:43:48 +00:00
|
|
|
if (curr->ai_family == AF_INET) {
|
2021-04-28 12:37:23 +00:00
|
|
|
if (bind(sock, (struct sockaddr*)&net4bind, sizeof(struct sockaddr_in)) < 0) {
|
|
|
|
fprintf(stderr, "Unable to bind port 302\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
2019-08-09 20:43:48 +00:00
|
|
|
} else if (curr->ai_family == AF_INET6) {
|
2021-04-28 12:37:23 +00:00
|
|
|
if (bind(sock, (struct sockaddr*)&net6bind, sizeof(struct sockaddr_in6)) < 0) {
|
|
|
|
fprintf(stderr, "Unable to bind port 302\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
2019-08-09 20:43:48 +00:00
|
|
|
} else {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (connect(sock, curr->ai_addr, curr->ai_addrlen) == 0) break;
|
|
|
|
}
|
|
|
|
if (curr == NULL) {
|
|
|
|
fprintf(stderr, "Unable to reach %s\n", argv[2]);
|
2019-08-08 20:14:05 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
2022-02-17 22:05:00 +00:00
|
|
|
if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0) {
|
|
|
|
fprintf(stderr, "Unable to set timeout\n");
|
|
|
|
}
|
2019-08-09 20:43:48 +00:00
|
|
|
freeaddrinfo(addrs);
|
2020-05-04 14:22:04 +00:00
|
|
|
ret = read(sock, buffer, 8);
|
2019-08-09 20:43:48 +00:00
|
|
|
if (memcmp(buffer, "\xc2\xd1-\xa8\x80\xd8j\xba", 8) != 0) {
|
|
|
|
fprintf(stderr, "Unrecognized server\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
2020-05-04 21:27:22 +00:00
|
|
|
slen = strlen(argv[1]) & 0xff;
|
|
|
|
dprintf(sock, "\x01%c%s", slen, argv[1]);
|
2022-03-08 19:46:00 +00:00
|
|
|
if (hmackeysize) {
|
|
|
|
ret = write(sock, "\x06\x20", 2);
|
|
|
|
ret = write(sock, hmac, 32);
|
|
|
|
} else
|
|
|
|
ret = write(sock, "\x00\x00", 2);
|
2019-08-09 20:43:48 +00:00
|
|
|
memset(buffer, 0, MAXPACKET);
|
2020-05-04 14:22:04 +00:00
|
|
|
ret = read(sock, buffer, 2);
|
2019-08-09 20:43:48 +00:00
|
|
|
while (buffer[0] != 255) {
|
|
|
|
currtype = buffer[0];
|
2020-11-06 15:00:36 +00:00
|
|
|
if (currtype & 0b10000000) {
|
2020-11-06 18:38:37 +00:00
|
|
|
currlen = buffer[1] << 8;
|
2021-06-03 21:05:54 +00:00
|
|
|
while (read(sock, buffer, 1) < 0) {};
|
2020-11-06 18:38:37 +00:00
|
|
|
currlen |= buffer[0];
|
2020-11-06 15:00:36 +00:00
|
|
|
} else {
|
|
|
|
currlen = buffer[1];
|
|
|
|
}
|
2019-08-09 20:43:48 +00:00
|
|
|
memset(buffer, 0, MAXPACKET);
|
2020-11-06 15:00:36 +00:00
|
|
|
if (currlen > 1000) {
|
|
|
|
fprintf(stderr, "Received oversized message\n");
|
2022-02-17 22:05:00 +00:00
|
|
|
exit(1);
|
2020-11-06 15:00:36 +00:00
|
|
|
}
|
2019-08-09 20:43:48 +00:00
|
|
|
if (currlen) {
|
2020-11-06 15:00:36 +00:00
|
|
|
ret = read(sock, buffer, currlen); // Max is 1000, well under MAX_PACKET
|
2020-11-06 18:57:35 +00:00
|
|
|
buffer[currlen] = 0;
|
2019-08-09 20:43:48 +00:00
|
|
|
}
|
|
|
|
if (currtype == 2) {
|
2021-06-04 21:19:19 +00:00
|
|
|
dprintf(sock, "\x03%c", (int)currlen);
|
2020-05-04 14:22:04 +00:00
|
|
|
ret = write(sock, buffer, currlen);
|
2020-05-04 21:27:22 +00:00
|
|
|
slen = strlen(cryptedpass) & 0xff;
|
|
|
|
dprintf(sock, "\x04%c%s", slen, cryptedpass);
|
2020-05-04 14:22:04 +00:00
|
|
|
ret = write(sock, "\x00\x00", 2);
|
2020-11-06 15:00:36 +00:00
|
|
|
} else if (currtype == 128) {
|
2022-02-17 22:05:00 +00:00
|
|
|
printf("SEALED:%s", buffer);
|
|
|
|
printf("\n");
|
|
|
|
exit(0);
|
2019-08-09 20:43:48 +00:00
|
|
|
} else if (currtype == 5) {
|
2020-05-04 14:22:04 +00:00
|
|
|
printf("%s", passwd);
|
2019-08-09 20:43:48 +00:00
|
|
|
printf("\n");
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
buffer[0] = 255;
|
2020-05-04 14:22:04 +00:00
|
|
|
ret = read(sock, buffer, 2);
|
2019-08-09 20:43:48 +00:00
|
|
|
}
|
|
|
|
fprintf(stderr, "Password was not accepted\n");
|
|
|
|
exit(1);
|
2019-08-08 20:14:05 +00:00
|
|
|
}
|