2 * Sub-authentication Daemon: Temporary Tokens
4 * (c) 2017 Martin Mares <mj@ucw.cz>
9 #include <ucw/base64.h>
11 #include <ucw/stkstring.h>
12 #include <ucw/string.h>
13 #include <ucw/unaligned.h>
23 // FIXME: Re-defined to handle const strings properly
24 #undef stk_strmulticat
25 #define stk_strmulticat(s...) ({ const char *_s[]={s}; char *_x=alloca(stk_array_len((char **)_s, ARRAY_SIZE(_s)-1)); stk_array_join(_x, (char **)_s, ARRAY_SIZE(_s)-1, 0); _x; })
27 #define TEMP_KEY_SIZE 32
28 #define TEMP_NONCE_SIZE 16
29 #define TEMP_SIGN_SIZE 16 // SHA2-256 HMAC
31 static byte temp_key[TEMP_KEY_SIZE];
33 static void temp_sign(byte *sig_text, char *raw_token)
35 // Sign the nonce with the temp key using SHA2-256 HMAC
37 if (gcry_md_open(&md, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC) != GPG_ERR_NO_ERROR)
38 die("gcry_md_open(CGRY_MD_SHA256) failed");
39 if (gcry_md_setkey(md, temp_key, TEMP_KEY_SIZE) != GPG_ERR_NO_ERROR)
40 die("gcry_md_setkey() failed");
42 gcry_md_write(md, raw_token, strlen(raw_token));
44 uint sig_len = base64_encode(sig_text, gcry_md_read(md, 0), TEMP_SIGN_SIZE);
45 sig_text[sig_len] = 0;
50 char *temp_generate(const char *zone, const char *login, uint validity)
52 byte nonce[TEMP_NONCE_SIZE];
53 gcry_randomize(nonce, TEMP_NONCE_SIZE, GCRY_STRONG_RANDOM);
55 char nonce_text[2*TEMP_NONCE_SIZE + 1];
56 uint nonce_len = base64_encode(nonce_text, nonce, TEMP_NONCE_SIZE);
57 nonce_text[nonce_len] = 0;
59 unsigned long long expire = time(NULL) + validity;
61 int expire_len = snprintf(expire_text, sizeof(expire_text), "%lld", expire);
62 ASSERT(expire_len < (int) sizeof(expire_text));
64 char *raw_token = stk_strmulticat((char *) zone, "-", login, "-", nonce_text, "-", expire_text, NULL);
66 char sig_text[2*TEMP_SIGN_SIZE + 1];
67 temp_sign(sig_text, raw_token);
69 return xstrdup(stk_strmulticat("t-", nonce_text, "-", expire_text, "-", sig_text, NULL));
72 const char *temp_check(const char *zone, const char *login, const char *token)
74 // Split and check format
75 // FIXME: Refuse tokens which are too long
77 if (str_sepsplit(stk_strdup(token), '-', fields, 4) != 4)
78 return "Wrong format";
79 if (!strcmp(fields[0], "t"))
80 return "Wrong format";
83 char *raw_token = stk_strmulticat(zone, "-", login, "-", fields[1], "-", fields[2], NULL);
84 char sig_text[2*TEMP_SIGN_SIZE + 1];
85 temp_sign(sig_text, raw_token);
86 if (strcmp(sig_text, fields[3]))
87 return "Wrong signature";
90 unsigned long long expire;
91 if (sscanf(fields[2], "%lld", &expire) != 1)
92 return "Wrong format";
93 if (expire < (unsigned long long) time(NULL))
104 int fd = open(temp_key_file, O_RDONLY);
107 int n = read(fd, temp_key, TEMP_KEY_SIZE);
108 if (n != TEMP_KEY_SIZE)
109 die("Cannot read temporary token key from %s", temp_key_file);
111 msg(L_INFO, "Loaded temporary token key from %s", temp_key_file);
116 gcry_randomize(temp_key_file, TEMP_KEY_SIZE, GCRY_STRONG_RANDOM);
117 msg(L_INFO, "Generated new temporary token key");
121 int fd = open(temp_key_file, O_WRONLY | O_CREAT | O_TRUNC, 0600);
123 die("Cannot create %s: %m", temp_key_file);
124 int n = write(fd, temp_key, TEMP_KEY_SIZE);
125 if (n != TEMP_KEY_SIZE)
126 die("Cannot write temporary token key");