Line data Source code
1 : /* genkey.c - Generate a keypair
2 : * Copyright (C) 2002, 2003, 2004, 2007, 2010 Free Software Foundation, Inc.
3 : * Copyright (C) 2015 g10 Code GmbH.
4 : *
5 : * This file is part of GnuPG.
6 : *
7 : * GnuPG is free software; you can redistribute it and/or modify
8 : * it under the terms of the GNU General Public License as published by
9 : * the Free Software Foundation; either version 3 of the License, or
10 : * (at your option) any later version.
11 : *
12 : * GnuPG is distributed in the hope that it will be useful,
13 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : * GNU General Public License for more details.
16 : *
17 : * You should have received a copy of the GNU General Public License
18 : * along with this program; if not, see <https://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include <config.h>
22 : #include <errno.h>
23 : #include <stdio.h>
24 : #include <stdlib.h>
25 : #include <string.h>
26 : #include <ctype.h>
27 : #include <assert.h>
28 :
29 : #include "agent.h"
30 : #include "i18n.h"
31 : #include "exechelp.h"
32 : #include "sysutils.h"
33 :
34 : static int
35 5 : store_key (gcry_sexp_t private, const char *passphrase, int force,
36 : unsigned long s2k_count)
37 : {
38 : int rc;
39 : unsigned char *buf;
40 : size_t len;
41 : unsigned char grip[20];
42 :
43 5 : if ( !gcry_pk_get_keygrip (private, grip) )
44 : {
45 0 : log_error ("can't calculate keygrip\n");
46 0 : return gpg_error (GPG_ERR_GENERAL);
47 : }
48 :
49 5 : len = gcry_sexp_sprint (private, GCRYSEXP_FMT_CANON, NULL, 0);
50 5 : assert (len);
51 5 : buf = gcry_malloc_secure (len);
52 5 : if (!buf)
53 0 : return out_of_core ();
54 5 : len = gcry_sexp_sprint (private, GCRYSEXP_FMT_CANON, buf, len);
55 5 : assert (len);
56 :
57 5 : if (passphrase)
58 : {
59 : unsigned char *p;
60 :
61 2 : rc = agent_protect (buf, passphrase, &p, &len, s2k_count, -1);
62 2 : if (rc)
63 : {
64 0 : xfree (buf);
65 0 : return rc;
66 : }
67 2 : xfree (buf);
68 2 : buf = p;
69 : }
70 :
71 5 : rc = agent_write_private_key (grip, buf, len, force);
72 5 : xfree (buf);
73 5 : return rc;
74 : }
75 :
76 :
77 : /* Count the number of non-alpha characters in S. Control characters
78 : and non-ascii characters are not considered. */
79 : static size_t
80 1 : nonalpha_count (const char *s)
81 : {
82 : size_t n;
83 :
84 5 : for (n=0; *s; s++)
85 4 : if (isascii (*s) && ( isdigit (*s) || ispunct (*s) ))
86 0 : n++;
87 :
88 1 : return n;
89 : }
90 :
91 :
92 : /* Check PW against a list of pattern. Return 0 if PW does not match
93 : these pattern. */
94 : static int
95 0 : check_passphrase_pattern (ctrl_t ctrl, const char *pw)
96 : {
97 0 : gpg_error_t err = 0;
98 0 : const char *pgmname = gnupg_module_name (GNUPG_MODULE_NAME_CHECK_PATTERN);
99 : FILE *infp;
100 : const char *argv[10];
101 : pid_t pid;
102 : int result, i;
103 :
104 : (void)ctrl;
105 :
106 0 : infp = gnupg_tmpfile ();
107 0 : if (!infp)
108 : {
109 0 : err = gpg_error_from_syserror ();
110 0 : log_error (_("error creating temporary file: %s\n"), gpg_strerror (err));
111 0 : return 1; /* Error - assume password should not be used. */
112 : }
113 :
114 0 : if (fwrite (pw, strlen (pw), 1, infp) != 1)
115 : {
116 0 : err = gpg_error_from_syserror ();
117 0 : log_error (_("error writing to temporary file: %s\n"),
118 : gpg_strerror (err));
119 0 : fclose (infp);
120 0 : return 1; /* Error - assume password should not be used. */
121 : }
122 0 : fseek (infp, 0, SEEK_SET);
123 0 : clearerr (infp);
124 :
125 0 : i = 0;
126 0 : argv[i++] = "--null";
127 0 : argv[i++] = "--",
128 0 : argv[i++] = opt.check_passphrase_pattern,
129 0 : argv[i] = NULL;
130 0 : assert (i < sizeof argv);
131 :
132 0 : if (gnupg_spawn_process_fd (pgmname, argv, fileno (infp), -1, -1, &pid))
133 0 : result = 1; /* Execute error - assume password should no be used. */
134 0 : else if (gnupg_wait_process (pgmname, pid, 1, NULL))
135 0 : result = 1; /* Helper returned an error - probably a match. */
136 : else
137 0 : result = 0; /* Success; i.e. no match. */
138 0 : gnupg_release_process (pid);
139 :
140 : /* Overwrite our temporary file. */
141 0 : fseek (infp, 0, SEEK_SET);
142 0 : clearerr (infp);
143 0 : for (i=((strlen (pw)+99)/100)*100; i > 0; i--)
144 0 : putc ('\xff', infp);
145 0 : fflush (infp);
146 0 : fclose (infp);
147 0 : return result;
148 : }
149 :
150 :
151 : static int
152 1 : take_this_one_anyway2 (ctrl_t ctrl, const char *desc, const char *anyway_btn)
153 : {
154 : gpg_error_t err;
155 :
156 1 : if (opt.enforce_passphrase_constraints)
157 : {
158 0 : err = agent_show_message (ctrl, desc, L_("Enter new passphrase"));
159 0 : if (!err)
160 0 : err = gpg_error (GPG_ERR_CANCELED);
161 : }
162 : else
163 1 : err = agent_get_confirmation (ctrl, desc,
164 : anyway_btn, L_("Enter new passphrase"), 0);
165 1 : return err;
166 : }
167 :
168 :
169 : static int
170 1 : take_this_one_anyway (ctrl_t ctrl, const char *desc)
171 : {
172 1 : return take_this_one_anyway2 (ctrl, desc, L_("Take this one anyway"));
173 : }
174 :
175 :
176 : /* Check whether the passphrase PW is suitable. Returns 0 if the
177 : passphrase is suitable and true if it is not and the user should be
178 : asked to provide a different one. If FAILED_CONSTRAINT is set, a
179 : message describing the problem is returned in
180 : *FAILED_CONSTRAINT. */
181 : int
182 1 : check_passphrase_constraints (ctrl_t ctrl, const char *pw,
183 : char **failed_constraint)
184 : {
185 1 : gpg_error_t err = 0;
186 1 : unsigned int minlen = opt.min_passphrase_len;
187 1 : unsigned int minnonalpha = opt.min_passphrase_nonalpha;
188 1 : char *msg1 = NULL;
189 1 : char *msg2 = NULL;
190 1 : char *msg3 = NULL;
191 :
192 1 : if (ctrl && ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK)
193 0 : return 0;
194 :
195 1 : if (!pw)
196 0 : pw = "";
197 :
198 : /* The first check is to warn about an empty passphrase. */
199 1 : if (!*pw)
200 : {
201 0 : const char *desc = (opt.enforce_passphrase_constraints?
202 : L_("You have not entered a passphrase!%0A"
203 0 : "An empty passphrase is not allowed.") :
204 : L_("You have not entered a passphrase - "
205 : "this is in general a bad idea!%0A"
206 : "Please confirm that you do not want to "
207 : "have any protection on your key."));
208 :
209 0 : err = 1;
210 0 : if (failed_constraint)
211 : {
212 0 : if (opt.enforce_passphrase_constraints)
213 0 : *failed_constraint = xstrdup (desc);
214 : else
215 0 : err = take_this_one_anyway2 (ctrl, desc,
216 : L_("Yes, protection is not needed"));
217 : }
218 :
219 0 : goto leave;
220 : }
221 :
222 : /* Now check the constraints and collect the error messages unless
223 : in in silent mode which returns immediately. */
224 1 : if (utf8_charcount (pw, -1) < minlen )
225 : {
226 1 : if (!failed_constraint)
227 : {
228 0 : err = gpg_error (GPG_ERR_INV_PASSPHRASE);
229 0 : goto leave;
230 : }
231 :
232 1 : msg1 = xtryasprintf
233 1 : ( ngettext ("A passphrase should be at least %u character long.",
234 : "A passphrase should be at least %u characters long.",
235 : minlen), minlen );
236 1 : if (!msg1)
237 : {
238 0 : err = gpg_error_from_syserror ();
239 0 : goto leave;
240 : }
241 : }
242 :
243 1 : if (nonalpha_count (pw) < minnonalpha )
244 : {
245 1 : if (!failed_constraint)
246 : {
247 0 : err = gpg_error (GPG_ERR_INV_PASSPHRASE);
248 0 : goto leave;
249 : }
250 :
251 1 : msg2 = xtryasprintf
252 1 : ( ngettext ("A passphrase should contain at least %u digit or%%0A"
253 : "special character.",
254 : "A passphrase should contain at least %u digits or%%0A"
255 : "special characters.",
256 : minnonalpha), minnonalpha );
257 1 : if (!msg2)
258 : {
259 0 : err = gpg_error_from_syserror ();
260 0 : goto leave;
261 : }
262 : }
263 :
264 : /* If configured check the passphrase against a list of known words
265 : and pattern. The actual test is done by an external program.
266 : The warning message is generic to give the user no hint on how to
267 : circumvent this list. */
268 1 : if (*pw && opt.check_passphrase_pattern &&
269 0 : check_passphrase_pattern (ctrl, pw))
270 : {
271 0 : if (!failed_constraint)
272 : {
273 0 : err = gpg_error (GPG_ERR_INV_PASSPHRASE);
274 0 : goto leave;
275 : }
276 :
277 0 : msg3 = xtryasprintf
278 : (L_("A passphrase may not be a known term or match%%0A"
279 : "certain pattern."));
280 0 : if (!msg3)
281 : {
282 0 : err = gpg_error_from_syserror ();
283 0 : goto leave;
284 : }
285 : }
286 :
287 1 : if (failed_constraint && (msg1 || msg2 || msg3))
288 : {
289 : char *msg;
290 : size_t n;
291 :
292 1 : msg = strconcat
293 : (L_("Warning: You have entered an insecure passphrase."),
294 : "%0A%0A",
295 : msg1? msg1 : "", msg1? "%0A" : "",
296 : msg2? msg2 : "", msg2? "%0A" : "",
297 : msg3? msg3 : "", msg3? "%0A" : "",
298 : NULL);
299 1 : if (!msg)
300 : {
301 0 : err = gpg_error_from_syserror ();
302 0 : goto leave;
303 : }
304 : /* Strip a trailing "%0A". */
305 1 : n = strlen (msg);
306 1 : if (n > 3 && !strcmp (msg + n - 3, "%0A"))
307 1 : msg[n-3] = 0;
308 :
309 1 : err = 1;
310 1 : if (opt.enforce_passphrase_constraints)
311 0 : *failed_constraint = msg;
312 : else
313 : {
314 1 : err = take_this_one_anyway (ctrl, msg);
315 1 : xfree (msg);
316 : }
317 : }
318 :
319 : leave:
320 1 : xfree (msg1);
321 1 : xfree (msg2);
322 1 : xfree (msg3);
323 1 : return err;
324 : }
325 :
326 :
327 : /* Callback function to compare the first entered PIN with the one
328 : currently being entered. */
329 : static gpg_error_t
330 1 : reenter_compare_cb (struct pin_entry_info_s *pi)
331 : {
332 1 : const char *pin1 = pi->check_cb_arg;
333 :
334 1 : if (!strcmp (pin1, pi->pin))
335 1 : return 0; /* okay */
336 0 : return gpg_error (GPG_ERR_BAD_PASSPHRASE);
337 : }
338 :
339 :
340 : /* Ask the user for a new passphrase using PROMPT. On success the
341 : function returns 0 and store the passphrase at R_PASSPHRASE; if the
342 : user opted not to use a passphrase NULL will be stored there. The
343 : user needs to free the returned string. In case of an error and
344 : error code is returned and NULL stored at R_PASSPHRASE. */
345 : gpg_error_t
346 1 : agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt,
347 : char **r_passphrase)
348 : {
349 : gpg_error_t err;
350 1 : const char *text1 = prompt;
351 1 : const char *text2 = L_("Please re-enter this passphrase");
352 1 : char *initial_errtext = NULL;
353 : struct pin_entry_info_s *pi, *pi2;
354 :
355 1 : *r_passphrase = NULL;
356 :
357 1 : if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK)
358 : {
359 : size_t size;
360 0 : size_t len = 100;
361 : unsigned char *buffer;
362 :
363 0 : err = pinentry_loopback(ctrl, "NEW_PASSPHRASE", &buffer, &size, len);
364 0 : if (!err)
365 : {
366 0 : if (size)
367 : {
368 0 : buffer[size] = 0;
369 0 : *r_passphrase = buffer;
370 : }
371 : else
372 0 : *r_passphrase = NULL;
373 : }
374 0 : return err;
375 : }
376 :
377 1 : pi = gcry_calloc_secure (1, sizeof (*pi) + MAX_PASSPHRASE_LEN + 1);
378 1 : if (!pi)
379 0 : return gpg_error_from_syserror ();
380 1 : pi2 = gcry_calloc_secure (1, sizeof (*pi2) + MAX_PASSPHRASE_LEN + 1);
381 1 : if (!pi2)
382 : {
383 0 : err = gpg_error_from_syserror ();
384 0 : xfree (pi2);
385 0 : return err;
386 : }
387 1 : pi->max_length = MAX_PASSPHRASE_LEN + 1;
388 1 : pi->max_tries = 3;
389 1 : pi->with_qualitybar = 1;
390 1 : pi->with_repeat = 1;
391 1 : pi2->max_length = MAX_PASSPHRASE_LEN + 1;
392 1 : pi2->max_tries = 3;
393 1 : pi2->check_cb = reenter_compare_cb;
394 1 : pi2->check_cb_arg = pi->pin;
395 :
396 : next_try:
397 1 : err = agent_askpin (ctrl, text1, NULL, initial_errtext, pi, NULL, 0);
398 1 : xfree (initial_errtext);
399 1 : initial_errtext = NULL;
400 1 : if (!err)
401 : {
402 1 : if (check_passphrase_constraints (ctrl, pi->pin, &initial_errtext))
403 : {
404 0 : pi->failed_tries = 0;
405 0 : pi2->failed_tries = 0;
406 0 : goto next_try;
407 : }
408 : /* Unless the passphrase is empty or the pinentry told us that
409 : it already did the repetition check, ask to confirm it. */
410 1 : if (*pi->pin && !pi->repeat_okay)
411 : {
412 1 : err = agent_askpin (ctrl, text2, NULL, NULL, pi2, NULL, 0);
413 1 : if (gpg_err_code (err) == GPG_ERR_BAD_PASSPHRASE)
414 : { /* The re-entered one did not match and the user did not
415 : hit cancel. */
416 0 : initial_errtext = xtrystrdup (L_("does not match - try again"));
417 0 : if (initial_errtext)
418 0 : goto next_try;
419 0 : err = gpg_error_from_syserror ();
420 : }
421 : }
422 : }
423 :
424 1 : if (!err && *pi->pin)
425 : {
426 : /* User wants a passphrase. */
427 1 : *r_passphrase = xtrystrdup (pi->pin);
428 1 : if (!*r_passphrase)
429 0 : err = gpg_error_from_syserror ();
430 : }
431 :
432 1 : xfree (initial_errtext);
433 1 : xfree (pi2);
434 1 : xfree (pi);
435 1 : return err;
436 : }
437 :
438 :
439 :
440 : /* Generate a new keypair according to the parameters given in
441 : KEYPARAM. If CACHE_NONCE is given first try to lookup a passphrase
442 : using the cache nonce. If NO_PROTECTION is true the key will not
443 : be protected by a passphrase. If OVERRIDE_PASSPHRASE is true that
444 : passphrase will be used for the new key. */
445 : int
446 5 : agent_genkey (ctrl_t ctrl, const char *cache_nonce,
447 : const char *keyparam, size_t keyparamlen, int no_protection,
448 : const char *override_passphrase, int preset, membuf_t *outbuf)
449 : {
450 : gcry_sexp_t s_keyparam, s_key, s_private, s_public;
451 5 : char *passphrase_buffer = NULL;
452 : const char *passphrase;
453 : int rc;
454 : size_t len;
455 : char *buf;
456 :
457 5 : rc = gcry_sexp_sscan (&s_keyparam, NULL, keyparam, keyparamlen);
458 5 : if (rc)
459 : {
460 0 : log_error ("failed to convert keyparam: %s\n", gpg_strerror (rc));
461 0 : return gpg_error (GPG_ERR_INV_DATA);
462 : }
463 :
464 : /* Get the passphrase now, cause key generation may take a while. */
465 5 : if (override_passphrase)
466 0 : passphrase = override_passphrase;
467 5 : else if (no_protection || !cache_nonce)
468 4 : passphrase = NULL;
469 : else
470 : {
471 1 : passphrase_buffer = agent_get_cache (cache_nonce, CACHE_MODE_NONCE);
472 1 : passphrase = passphrase_buffer;
473 : }
474 :
475 5 : if (passphrase || no_protection)
476 : ;
477 : else
478 : {
479 1 : rc = agent_ask_new_passphrase (ctrl,
480 : L_("Please enter the passphrase to%0A"
481 : "protect your new key"),
482 : &passphrase_buffer);
483 1 : if (rc)
484 0 : return rc;
485 1 : passphrase = passphrase_buffer;
486 : }
487 :
488 5 : rc = gcry_pk_genkey (&s_key, s_keyparam );
489 5 : gcry_sexp_release (s_keyparam);
490 5 : if (rc)
491 : {
492 0 : log_error ("key generation failed: %s\n", gpg_strerror (rc));
493 0 : xfree (passphrase_buffer);
494 0 : return rc;
495 : }
496 :
497 : /* break out the parts */
498 5 : s_private = gcry_sexp_find_token (s_key, "private-key", 0);
499 5 : if (!s_private)
500 : {
501 0 : log_error ("key generation failed: invalid return value\n");
502 0 : gcry_sexp_release (s_key);
503 0 : xfree (passphrase_buffer);
504 0 : return gpg_error (GPG_ERR_INV_DATA);
505 : }
506 5 : s_public = gcry_sexp_find_token (s_key, "public-key", 0);
507 5 : if (!s_public)
508 : {
509 0 : log_error ("key generation failed: invalid return value\n");
510 0 : gcry_sexp_release (s_private);
511 0 : gcry_sexp_release (s_key);
512 0 : xfree (passphrase_buffer);
513 0 : return gpg_error (GPG_ERR_INV_DATA);
514 : }
515 5 : gcry_sexp_release (s_key); s_key = NULL;
516 :
517 : /* store the secret key */
518 5 : if (DBG_CRYPTO)
519 0 : log_debug ("storing private key\n");
520 5 : rc = store_key (s_private, passphrase, 0, ctrl->s2k_count);
521 5 : if (!rc)
522 : {
523 5 : if (!cache_nonce)
524 : {
525 : char tmpbuf[12];
526 4 : gcry_create_nonce (tmpbuf, 12);
527 4 : cache_nonce = bin2hex (tmpbuf, 12, NULL);
528 : }
529 5 : if (cache_nonce
530 5 : && !no_protection
531 2 : && !agent_put_cache (cache_nonce, CACHE_MODE_NONCE,
532 : passphrase, ctrl->cache_ttl_opt_preset))
533 2 : agent_write_status (ctrl, "CACHE_NONCE", cache_nonce, NULL);
534 5 : if (preset && !no_protection)
535 : {
536 : unsigned char grip[20];
537 : char hexgrip[40+1];
538 0 : if (gcry_pk_get_keygrip (s_private, grip))
539 : {
540 0 : bin2hex(grip, 20, hexgrip);
541 0 : rc = agent_put_cache (hexgrip, CACHE_MODE_ANY, passphrase,
542 : ctrl->cache_ttl_opt_preset);
543 : }
544 : }
545 : }
546 5 : xfree (passphrase_buffer);
547 5 : passphrase_buffer = NULL;
548 5 : passphrase = NULL;
549 5 : gcry_sexp_release (s_private);
550 5 : if (rc)
551 : {
552 0 : gcry_sexp_release (s_public);
553 0 : return rc;
554 : }
555 :
556 : /* return the public key */
557 5 : if (DBG_CRYPTO)
558 0 : log_debug ("returning public key\n");
559 5 : len = gcry_sexp_sprint (s_public, GCRYSEXP_FMT_CANON, NULL, 0);
560 5 : assert (len);
561 5 : buf = xtrymalloc (len);
562 5 : if (!buf)
563 : {
564 0 : gpg_error_t tmperr = out_of_core ();
565 0 : gcry_sexp_release (s_private);
566 0 : gcry_sexp_release (s_public);
567 0 : return tmperr;
568 : }
569 5 : len = gcry_sexp_sprint (s_public, GCRYSEXP_FMT_CANON, buf, len);
570 5 : assert (len);
571 5 : put_membuf (outbuf, buf, len);
572 5 : gcry_sexp_release (s_public);
573 5 : xfree (buf);
574 :
575 5 : return 0;
576 : }
577 :
578 :
579 :
580 : /* Apply a new passphrase to the key S_SKEY and store it. If
581 : PASSPHRASE_ADDR and *PASSPHRASE_ADDR are not NULL, use that
582 : passphrase. If PASSPHRASE_ADDR is not NULL store a newly entered
583 : passphrase at that address. */
584 : gpg_error_t
585 0 : agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey,
586 : char **passphrase_addr)
587 : {
588 : gpg_error_t err;
589 :
590 0 : if (passphrase_addr && *passphrase_addr)
591 : {
592 : /* Take an empty string as request not to protect the key. */
593 0 : err = store_key (s_skey, **passphrase_addr? *passphrase_addr:NULL, 1,
594 : ctrl->s2k_count);
595 : }
596 : else
597 : {
598 0 : char *pass = NULL;
599 :
600 0 : if (passphrase_addr)
601 : {
602 0 : xfree (*passphrase_addr);
603 0 : *passphrase_addr = NULL;
604 : }
605 0 : err = agent_ask_new_passphrase (ctrl,
606 : L_("Please enter the new passphrase"),
607 : &pass);
608 0 : if (!err)
609 0 : err = store_key (s_skey, pass, 1, ctrl->s2k_count);
610 0 : if (!err && passphrase_addr)
611 0 : *passphrase_addr = pass;
612 : else
613 0 : xfree (pass);
614 : }
615 :
616 0 : return err;
617 : }
|