encode_uint32 second parameter should be uint32_t, not unsigned long
[git-daemon2.git] / gensrpverifier.c
blob3d1decb5f7056b48e7db376932a1ad1625bf3c6c
1 /*
2 * Copyright (C) Ilari Liusvaara 2009-2010
4 * This code is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8 #include "prompt.h"
9 #include <stdio.h>
10 #include <string.h>
11 #include <gnutls/gnutls.h>
12 #include <unistd.h>
13 #include <fcntl.h>
14 #include <errno.h>
15 #include <string.h>
16 #include "home.h"
17 #ifdef USE_COMPAT_H
18 #include "compat.h"
19 #else
20 #include "git-compat-util.h"
21 #endif
23 static void do_help()
25 printf("gits-generate-srp-verifier: Generate SRP verifiers for\n");
26 printf("password authentication\n");
27 printf("Command line:\n");
28 printf("--help\n");
29 printf("\tThis help\n");
30 printf("\n");
31 printf("Note: Server needs SRP verifier in order to do password\n");
32 printf("authentication. Usernames are assigned by repostiory\n");
33 printf("hosting admin, just using arbitrary names doesn't work.\n");
34 exit(0);
38 struct field
40 const char *f_name;
41 const char *f_generator;
42 const char *f_prime;
45 struct field fields[] = {
47 "standard 1024 bit field", "2",
48 "Ewl2hcjiutMd3Fu2lgFnUXWSc67TVyy2vwYCKoS9MLsrdJVT9RgWTCuEqWJrfB6uE"
49 "3LsE9GkOlaZabS7M29sj5TnzUqOLJMjiwEzArfiLr9WbMRANlF68N5AVLcPWvNx6Z"
50 "jl3m5Scp0BzJBz9TkgfhzKJZ.WtP3Mv/67I/0wmRZ"
53 "standard 1536 bit field", "2",
54 "dUyyhxav9tgnyIg65wHxkzkb7VIPh4o0lkwfOKiPp4rVJrzLRYVBtb76gKlaO7ef5"
55 "LYGEw3G.4E0jbMxcYBetDy2YdpiP/3GWJInoBbvYHIRO9uBuxgsFKTKWu7RnR7yTa"
56 "u/IrFTdQ4LY/q.AvoCzMxV0PKvD9Odso/LFIItn8PbTov3VMn/ZEH2SqhtpBUkWtm"
57 "cIkEflhX/YY/fkBKfBbe27/zUaKUUZEUYZ2H2nlCL60.JIPeZJSzsu/xHDVcx"
60 "standard 2048 bit field", "2",
61 "2iQzj1CagQc/5ctbuJYLWlhtAsPHc7xWVyCPAKFRLWKADpASkqe9djWPFWTNTdeJt"
62 "L8nAhImCn3Sr/IAdQ1FrGw0WvQUstPx3FO9KNcXOwisOQ1VlL.gheAHYfbYyBaxXL"
63 ".NcJx9TUwgWDT0hRzFzqSrdGGTN3FgSTA1v4QnHtEygNj3eZ.u0MThqWUaDiP87nq"
64 "ha7XnT66bkTCkQ8.7T8L4KZjIImrNrUftedTTBi.WCi.zlrBxDuOM0da0JbUkQlXq"
65 "vp0yvJAPpC11nxmmZOAbQOywZGmu9nhZNuwTlxjfIro0FOdthaDTuZRL9VL7MRPUD"
66 "o/DQEyW.d4H.UIlzp"
68 {NULL, NULL, NULL}
72 unsigned char xfact[16] = {
73 0x9D, 0x0F, 0x49, 0xD4,
74 0x73, 0x88, 0xC7, 0xFF,
75 0xFD, 0x24, 0x6A, 0x0F,
76 0x94, 0x78, 0x0C, 0x14
79 unsigned char rnd[16] = {
80 0x00, 0x00, 0x00, 0x00,
81 0x00, 0x00, 0x00, 0x00,
82 0x00, 0x00, 0x00, 0x00,
83 0x00, 0x00, 0x00, 0x00
86 static void add(unsigned char *res, unsigned char *a, unsigned char *b)
88 unsigned char carry = 0;
89 unsigned i;
91 for (i = 0; i < 16; i++) {
92 unsigned char newcarry = 0;
94 if ((unsigned char)(a[i] + b[i]) < a[i])
95 newcarry++;
96 res[i] = a[i] + b[i];
97 if (res[i] + carry < res[i])
98 newcarry++;
99 res[i] += carry;
100 carry = newcarry;
102 while (carry) {
103 carry = 159;
105 for (i = 0; i < 16; i++) {
106 int newcarry = 0;
108 if ((unsigned char)(res[i] + carry) < res[i])
109 newcarry++;
110 res[i] += carry;
111 carry = newcarry;
114 for (i = 1; i < 16; i++)
115 if (res[i] < 255)
116 goto skip;
118 if (res[0] > 0x60) {
119 for (i = 1; i < 16; i++)
120 res[i] = 0;
121 res[0] -= 0x61;
123 skip:
127 void update_xfact()
129 unsigned char xfact2[16];
130 unsigned char xfact4[16];
131 unsigned char xfact5[16];
132 add(xfact2, xfact, xfact);
133 add(xfact4, xfact2, xfact2);
134 add(xfact5, xfact4, xfact);
135 memcpy(xfact, xfact5, 16);
138 void update_rnd(unsigned char ch)
140 unsigned char rndt[16];
141 unsigned i;
142 for (i = 0; i < 8; i++) {
143 if ((ch >> i) % 2) {
144 add(rndt, rnd, xfact);
145 memcpy(rnd, rndt, 16);
147 update_xfact();
151 void update_rnd_str(const char *ch)
153 while (ch && *ch)
154 update_rnd((unsigned char)*(ch++));
158 void decode_element(gnutls_datum_t *decode, const char *encoded)
160 int s;
161 gnutls_datum_t _base64;
162 size_t base64len, reslen, reslen2;
164 base64len = strlen(encoded);
165 reslen2 = reslen = (3 * base64len + 1) / 4;
167 _base64.data = (unsigned char*)encoded;
168 _base64.size = base64len;
170 decode->size = reslen;
171 decode->data = xmalloc(reslen);
172 s = gnutls_srp_base64_decode(&_base64, (char*)decode->data, &reslen2);
173 if (s < 0)
174 die("Unable to decode base64 data");
175 else if (reslen != reslen2)
176 die("Base64 dlength calculation incorrect. Calculated %lu, "
177 "got %lu", (unsigned long)reslen, (unsigned long)reslen2);
180 unsigned char *encode_element(gnutls_datum_t *data)
182 int s;
183 size_t reslen2;
184 unsigned char *res;
186 reslen2 = (4 * data->size + 2) / 3;
188 res = xmalloc(reslen2 + 1);
189 s = gnutls_srp_base64_encode(data, (char*)res, &reslen2);
190 if (s < 0)
191 die("Unable to encode base64 data");
192 res[reslen2] = '\0';
193 return res;
196 char *generate_srp_line(const char *username,
197 const char *password, const char *junk, struct field *field)
199 gnutls_datum_t salt;
200 gnutls_datum_t g;
201 gnutls_datum_t n;
202 gnutls_datum_t res;
203 int s;
204 char *retline = NULL;
205 unsigned char *encoded_salt;
206 unsigned char *encoded_verifier;
207 update_rnd_str(username);
208 update_rnd_str(":::::");
209 update_rnd_str(junk);
211 salt.data = rnd;
212 salt.size = 16;
213 decode_element(&g, field->f_generator);
214 decode_element(&n, field->f_prime);
216 s = gnutls_srp_verifier(username, password, &salt, &g, &n, &res);
217 if (s < 0)
218 die("Unable to generate SRP verifier: %s",
219 gnutls_strerror(s));
221 encoded_verifier = encode_element(&res);
222 encoded_salt = encode_element(&salt);
224 retline = xmalloc(5 + strlen(username) +
225 strlen((char*)encoded_salt) +
226 strlen((char*)encoded_verifier) +
227 strlen(field->f_generator) +
228 strlen(field->f_prime));
229 retline[0] = '\0';
230 strcat(retline, username);
231 strcat(retline, ":");
232 strcat(retline, (char*)encoded_salt);
233 strcat(retline, ":");
234 strcat(retline, (char*)encoded_verifier);
235 strcat(retline, ":");
236 strcat(retline, field->f_generator);
237 strcat(retline, ":");
238 strcat(retline, field->f_prime);
240 free(encoded_verifier);
241 free(encoded_salt);
242 free(res.data);
243 free(g.data);
244 free(n.data);
246 return retline;
249 #define LINELEN 69
251 static void flush_to_file(FILE *out, const char *srpline)
253 char linebuffer[LINELEN + 2];
255 linebuffer[LINELEN] = '\\';
256 linebuffer[LINELEN + 1] = '\0';
258 while (*srpline) {
259 size_t r;
260 strncpy(linebuffer, srpline, LINELEN);
261 r = strlen(srpline);
262 if (r == LINELEN)
263 linebuffer[LINELEN] = '\0';
264 if (r <= LINELEN)
265 srpline += r;
266 else
267 srpline += LINELEN;
268 fprintf(out, "%s\n", linebuffer);
272 int fill_rnd()
274 int fd;
275 int fill = 0;
277 fd = open("/dev/urandom", O_RDONLY);
278 if (fd < 0)
279 return 0;
281 while (fill < 16) {
282 ssize_t r;
283 r = read(fd, rnd + fill, 16 - fill);
284 if (r < 0 && errno != EINTR && errno != EAGAIN) {
285 close(fd);
286 return 0;
287 } else if (r == 0) {
288 close(fd);
289 return 0;
290 } else {
291 fill += r;
294 close(fd);
295 return 1;
298 int main(int argc, char **argv)
300 int idx, midx = 0;
301 char *username = NULL;
302 char *password = NULL;
303 char *password2 = NULL;
304 char *junk = NULL;
305 char *field = NULL;
306 char *file = NULL;
307 char *ans = NULL;
308 char *end = NULL;
309 FILE *filp = stdout;
311 if (argc > 1 && !strcmp(argv[1], "--help"))
312 do_help();
314 username_again:
315 free(username);
316 username = prompt_string("Enter username", 0);
317 if (!*username) {
318 fprintf(stderr, "Error: Bad username\n");
319 goto username_again;
322 if (fill_rnd())
323 goto no_junk_prompt;
324 junk_again:
325 free(junk);
326 junk = prompt_string("Enter some garbage from keyboard (min 32 "
327 "chars)", 1);
328 if (strlen(junk) < 32) {
329 fprintf(stderr, "Error: Garbage needs to be at least "
330 "32 characters\n");
331 goto junk_again;
333 no_junk_prompt:
335 passwords_again:
336 free(password);
337 free(password2);
338 password = prompt_string("Enter password", 1);
339 password2 = prompt_string("Enter password again", 1);
340 if (strcmp(password, password2)) {
341 fprintf(stderr, "Error: Passwords don't match\n");
342 goto passwords_again;
345 field_again:
346 free(field);
347 for (midx = 0; fields[midx].f_name; midx++) {
348 printf("%i) %s\n", midx + 1, fields[midx].f_name);
350 field = prompt_string("Pick field", 0);
351 idx = (int)strtoul(field, &end, 10) - 1;
352 if (idx < 0 || idx >= midx || !*field || *end) {
353 printf("%i %i %i %i\n", idx, midx, *field, *end);
354 fprintf(stderr, "Error: Invalid choice\n");
355 goto field_again;
358 file_again:
359 file = prompt_string("Filename to save as (enter for dump to "
360 "terminal)", 0);
361 if (*file) {
362 int fd;
363 fd = open_create_dirs(file, O_CREAT | O_EXCL | O_WRONLY, 0600);
364 if (fd < 0) {
365 fprintf(stderr, "Can't open '%s': %s\n", file,
366 strerror(errno));
367 goto file_again;
369 filp = xfdopen(fd, "w");
372 ans = generate_srp_line(username, password, junk, fields + idx);
373 flush_to_file(filp, ans);
374 if (filp != stdout)
375 fclose(filp);
376 return 0;