aboutsummaryrefslogtreecommitdiff
path: root/src/util/crypto_rsa.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2012-07-14 21:19:22 +0000
committerChristian Grothoff <christian@grothoff.org>2012-07-14 21:19:22 +0000
commita299afa8af5593c2114ca8242099d8f7971c428e (patch)
treed6474062280de16f92cb7f2239393094dcf472cd /src/util/crypto_rsa.c
parent7958f822ccba4fe2dc372c62aaaa2b2d8fe56acf (diff)
downloadgnunet-a299afa8af5593c2114ca8242099d8f7971c428e.tar.gz
gnunet-a299afa8af5593c2114ca8242099d8f7971c428e.zip
-new API for asyncronous generation of private RSA keys
Diffstat (limited to 'src/util/crypto_rsa.c')
-rw-r--r--src/util/crypto_rsa.c358
1 files changed, 326 insertions, 32 deletions
diff --git a/src/util/crypto_rsa.c b/src/util/crypto_rsa.c
index bbd73083d..6e92f0753 100644
--- a/src/util/crypto_rsa.c
+++ b/src/util/crypto_rsa.c
@@ -34,9 +34,7 @@
34#include "platform.h" 34#include "platform.h"
35#include <gcrypt.h> 35#include <gcrypt.h>
36#include "gnunet_common.h" 36#include "gnunet_common.h"
37#include "gnunet_crypto_lib.h" 37#include "gnunet_util_lib.h"
38#include "gnunet_disk_lib.h"
39#include "gnunet_strings_lib.h"
40 38
41#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) 39#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
42 40
@@ -44,9 +42,10 @@
44 42
45#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename) 43#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
46 44
45
47/** 46/**
48 * The private information of an RSA key pair. 47 * The private information of an RSA key pair.
49 * NOTE: this must match the definition in crypto_ksk.c 48 * NOTE: this must match the definition in crypto_ksk.c and gnunet-rsa.c!
50 */ 49 */
51struct GNUNET_CRYPTO_RsaPrivateKey 50struct GNUNET_CRYPTO_RsaPrivateKey
52{ 51{
@@ -81,31 +80,6 @@ adjust (unsigned char *buf, size_t size, size_t target)
81 } 80 }
82} 81}
83 82
84/**
85 * Create a new private key. Caller must free return value.
86 *
87 * @return fresh private key
88 */
89struct GNUNET_CRYPTO_RsaPrivateKey *
90GNUNET_CRYPTO_rsa_key_create ()
91{
92 struct GNUNET_CRYPTO_RsaPrivateKey *ret;
93 gcry_sexp_t s_key;
94 gcry_sexp_t s_keyparam;
95
96 GNUNET_assert (0 ==
97 gcry_sexp_build (&s_keyparam, NULL,
98 "(genkey(rsa(nbits %d)(rsa-use-e 3:257)))",
99 HOSTKEY_LEN));
100 GNUNET_assert (0 == gcry_pk_genkey (&s_key, s_keyparam));
101 gcry_sexp_release (s_keyparam);
102#if EXTRA_CHECKS
103 GNUNET_assert (0 == gcry_pk_testkey (s_key));
104#endif
105 ret = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_RsaPrivateKey));
106 ret->sexp = s_key;
107 return ret;
108}
109 83
110/** 84/**
111 * Free memory occupied by hostkey 85 * Free memory occupied by hostkey
@@ -118,6 +92,10 @@ GNUNET_CRYPTO_rsa_key_free (struct GNUNET_CRYPTO_RsaPrivateKey *hostkey)
118 GNUNET_free (hostkey); 92 GNUNET_free (hostkey);
119} 93}
120 94
95
96/**
97 * FIXME: document!
98 */
121static int 99static int
122key_from_sexp (gcry_mpi_t * array, gcry_sexp_t sexp, const char *topname, 100key_from_sexp (gcry_mpi_t * array, gcry_sexp_t sexp, const char *topname,
123 const char *elems) 101 const char *elems)
@@ -594,6 +572,98 @@ GNUNET_CRYPTO_rsa_decode_key (const char *buf, uint16_t len)
594 572
595 573
596/** 574/**
575 * Create a new private key. Caller must free return value.
576 *
577 * @return fresh private key
578 */
579static struct GNUNET_CRYPTO_RsaPrivateKey *
580rsa_key_create ()
581{
582 struct GNUNET_CRYPTO_RsaPrivateKey *ret;
583 gcry_sexp_t s_key;
584 gcry_sexp_t s_keyparam;
585
586 GNUNET_assert (0 ==
587 gcry_sexp_build (&s_keyparam, NULL,
588 "(genkey(rsa(nbits %d)(rsa-use-e 3:257)))",
589 HOSTKEY_LEN));
590 GNUNET_assert (0 == gcry_pk_genkey (&s_key, s_keyparam));
591 gcry_sexp_release (s_keyparam);
592#if EXTRA_CHECKS
593 GNUNET_assert (0 == gcry_pk_testkey (s_key));
594#endif
595 ret = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_RsaPrivateKey));
596 ret->sexp = s_key;
597 return ret;
598}
599
600
601/**
602 * Try to read the private key from the given file.
603 *
604 * @param filename file to read the key from
605 * @return NULL on error
606 */
607static struct GNUNET_CRYPTO_RsaPrivateKey *
608try_read_key (const char *filename)
609{
610 struct GNUNET_CRYPTO_RsaPrivateKey *ret;
611 struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded *enc;
612 struct GNUNET_DISK_FileHandle *fd;
613 OFF_T fs;
614 uint16_t len;
615
616 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
617 return NULL;
618
619 /* hostkey file exists already, read it! */
620 if (NULL == (fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ,
621 GNUNET_DISK_PERM_NONE)))
622 {
623 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename);
624 return NULL;
625 }
626 if (GNUNET_OK != (GNUNET_DISK_file_handle_size (fd, &fs)))
627 {
628 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "stat", filename);
629 (void) GNUNET_DISK_file_close (fd);
630 return NULL;
631 }
632 if (fs > UINT16_MAX)
633 {
634 LOG (GNUNET_ERROR_TYPE_ERROR,
635 _("File `%s' does not contain a valid private key. Deleting it.\n"),
636 filename);
637 GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fd));
638 if (0 != UNLINK (filename))
639 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", filename);
640 return NULL;
641 }
642
643 enc = GNUNET_malloc (fs);
644 GNUNET_break (fs == GNUNET_DISK_file_read (fd, enc, fs));
645 len = ntohs (enc->len);
646 ret = NULL;
647 if ((len != fs) ||
648 (NULL == (ret = GNUNET_CRYPTO_rsa_decode_key ((char *) enc, len))))
649 {
650 LOG (GNUNET_ERROR_TYPE_ERROR,
651 _("File `%s' does not contain a valid private key. Deleting it.\n"),
652 filename);
653 GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fd));
654 if (0 != UNLINK (filename))
655 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", filename);
656 GNUNET_free (enc);
657 return NULL;
658 }
659 GNUNET_free (enc);
660
661 GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fd));
662 return ret;
663}
664
665
666/**
597 * Create a new private key by reading it from a file. If the 667 * Create a new private key by reading it from a file. If the
598 * files does not exist, create a new key and write it to the 668 * files does not exist, create a new key and write it to the
599 * file. Caller must free return value. Note that this function 669 * file. Caller must free return value. Note that this function
@@ -658,13 +728,13 @@ GNUNET_CRYPTO_rsa_key_create_from_file (const char *filename)
658 { 728 {
659 ec = errno; 729 ec = errno;
660 LOG (GNUNET_ERROR_TYPE_ERROR, 730 LOG (GNUNET_ERROR_TYPE_ERROR,
661 _("Could not aquire lock on file `%s': %s...\n"), filename, 731 _("Could not acquire lock on file `%s': %s...\n"), filename,
662 STRERROR (ec)); 732 STRERROR (ec));
663 } 733 }
664 } 734 }
665 LOG (GNUNET_ERROR_TYPE_INFO, 735 LOG (GNUNET_ERROR_TYPE_INFO,
666 _("Creating a new private key. This may take a while.\n")); 736 _("Creating a new private key. This may take a while.\n"));
667 ret = GNUNET_CRYPTO_rsa_key_create (); 737 ret = rsa_key_create ();
668 GNUNET_assert (ret != NULL); 738 GNUNET_assert (ret != NULL);
669 enc = GNUNET_CRYPTO_rsa_encode_key (ret); 739 enc = GNUNET_CRYPTO_rsa_encode_key (ret);
670 GNUNET_assert (enc != NULL); 740 GNUNET_assert (enc != NULL);
@@ -705,7 +775,7 @@ GNUNET_CRYPTO_rsa_key_create_from_file (const char *filename)
705 { 775 {
706 ec = errno; 776 ec = errno;
707 LOG (GNUNET_ERROR_TYPE_ERROR, 777 LOG (GNUNET_ERROR_TYPE_ERROR,
708 _("Could not aquire lock on file `%s': %s...\n"), filename, 778 _("Could not acquire lock on file `%s': %s...\n"), filename,
709 STRERROR (ec)); 779 STRERROR (ec));
710 LOG (GNUNET_ERROR_TYPE_ERROR, 780 LOG (GNUNET_ERROR_TYPE_ERROR,
711 _ 781 _
@@ -786,6 +856,230 @@ GNUNET_CRYPTO_rsa_key_create_from_file (const char *filename)
786 856
787 857
788/** 858/**
859 * Handle to cancel private key generation and state for the
860 * key generation operation.
861 */
862struct GNUNET_CRYPTO_RsaKeyGenerationContext
863{
864
865 /**
866 * Continuation to call upon completion.
867 */
868 GNUNET_CRYPTO_RsaKeyCallback cont;
869
870 /**
871 * Closure for 'cont'.
872 */
873 void *cont_cls;
874
875 /**
876 * Name of the file.
877 */
878 char *filename;
879
880 /**
881 * Handle to the helper process which does the key generation.
882 */
883 struct GNUNET_OS_Process *gnunet_rsa;
884
885 /**
886 * Handle to 'stdout' of gnunet-rsa. We 'read' on stdout to detect
887 * process termination (instead of messing with SIGCHLD).
888 */
889 struct GNUNET_DISK_PipeHandle *gnunet_rsa_out;
890
891 /**
892 * Location where we store the private key if it already existed.
893 * (if this is used, 'filename', 'gnunet_rsa' and 'gnunet_rsa_out' will
894 * not be used).
895 */
896 struct GNUNET_CRYPTO_RsaPrivateKey *pk;
897
898 /**
899 * Task reading from 'gnunet_rsa_out' to wait for process termination.
900 */
901 GNUNET_SCHEDULER_TaskIdentifier read_task;
902
903};
904
905
906/**
907 * Task called upon shutdown or process termination of 'gnunet-rsa' during
908 * RSA key generation. Check where we are and perform the appropriate
909 * action.
910 *
911 * @param cls the 'struct GNUNET_CRYPTO_RsaKeyGenerationContext'
912 * @param tc scheduler context
913 */
914static void
915check_key_generation_completion (void *cls,
916 const struct GNUNET_SCHEDULER_TaskContext *tc)
917{
918 struct GNUNET_CRYPTO_RsaKeyGenerationContext *gc = cls;
919 enum GNUNET_OS_ProcessStatusType type;
920 unsigned long code;
921 struct GNUNET_CRYPTO_RsaPrivateKey *pk;
922
923 gc->read_task = GNUNET_SCHEDULER_NO_TASK;
924 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
925 {
926 gc->cont (gc->cont_cls, NULL, _("interrupted by shutdown"));
927 GNUNET_CRYPTO_rsa_key_create_stop (gc);
928 return;
929 }
930 if (GNUNET_OK !=
931 GNUNET_OS_process_status (gc->gnunet_rsa,
932 &type, &code))
933 {
934 GNUNET_break (0);
935 gc->cont (gc->cont_cls, NULL, _("internal error"));
936 GNUNET_CRYPTO_rsa_key_create_stop (gc);
937 return;
938 }
939 GNUNET_OS_process_destroy (gc->gnunet_rsa);
940 gc->gnunet_rsa = NULL;
941 if ( (GNUNET_OS_PROCESS_EXITED != type) ||
942 (0 != code) )
943 {
944 gc->cont (gc->cont_cls, NULL, _("gnunet-rsa failed"));
945 GNUNET_CRYPTO_rsa_key_create_stop (gc);
946 return;
947 }
948 if (NULL == (pk = try_read_key (gc->filename)))
949 {
950 GNUNET_break (0);
951 gc->cont (gc->cont_cls, NULL, _("gnunet-rsa failed"));
952 GNUNET_CRYPTO_rsa_key_create_stop (gc);
953 return;
954 }
955 gc->cont (gc->cont_cls, pk, NULL);
956 GNUNET_free (gc->filename);
957 GNUNET_free (gc);
958}
959
960
961/**
962 * Return the private RSA key which already existed on disk
963 * (asynchronously) to the caller.
964 *
965 * @param cls the 'struct GNUNET_CRYPTO_RsaKeyGenerationContext'
966 * @param tc scheduler context (unused)
967 */
968static void
969async_return_key (void *cls,
970 const struct GNUNET_SCHEDULER_TaskContext *tc)
971{
972 struct GNUNET_CRYPTO_RsaKeyGenerationContext *gc = cls;
973
974 gc->cont (gc->cont_cls,
975 gc->pk,
976 NULL);
977 GNUNET_free (gc);
978}
979
980
981/**
982 * Create a new private key by reading it from a file. If the files
983 * does not exist, create a new key and write it to the file. If the
984 * contents of the file are invalid the old file is deleted and a
985 * fresh key is created.
986 *
987 * @param filename name of file to use for storage
988 * @param cont function to call when done (or on errors)
989 * @param cont_cls closure for 'cont'
990 * @return handle to abort operation, NULL on fatal errors (cont will not be called if NULL is returned)
991 */
992struct GNUNET_CRYPTO_RsaKeyGenerationContext *
993GNUNET_CRYPTO_rsa_key_create_start (const char *filename,
994 GNUNET_CRYPTO_RsaKeyCallback cont,
995 void *cont_cls)
996{
997 struct GNUNET_CRYPTO_RsaKeyGenerationContext *gc;
998 struct GNUNET_CRYPTO_RsaPrivateKey *pk;
999
1000 if (NULL != (pk = try_read_key (filename)))
1001 {
1002 /* quick happy ending: key already exists! */
1003 gc = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_RsaKeyGenerationContext));
1004 gc->pk = pk;
1005 gc->cont = cont;
1006 gc->cont_cls = cont_cls;
1007 gc->read_task = GNUNET_SCHEDULER_add_now (&async_return_key,
1008 gc);
1009 return gc;
1010 }
1011 gc = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_RsaKeyGenerationContext));
1012 gc->filename = GNUNET_strdup (filename);
1013 gc->cont = cont;
1014 gc->cont_cls = cont_cls;
1015 gc->gnunet_rsa_out = GNUNET_DISK_pipe (GNUNET_NO,
1016 GNUNET_NO,
1017 GNUNET_NO,
1018 GNUNET_YES);
1019 if (NULL == gc->gnunet_rsa_out)
1020 {
1021 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "pipe");
1022 GNUNET_free (gc->filename);
1023 GNUNET_free (gc);
1024 return NULL;
1025 }
1026 gc->gnunet_rsa = GNUNET_OS_start_process (GNUNET_YES,
1027 GNUNET_OS_INHERIT_STD_ERR,
1028 NULL,
1029 gc->gnunet_rsa_out,
1030 "gnunet-rsa",
1031 "gnunet-rsa",
1032 gc->filename,
1033 NULL);
1034 if (NULL == gc->gnunet_rsa)
1035 {
1036 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "fork");
1037 GNUNET_DISK_pipe_close (gc->gnunet_rsa_out);
1038 GNUNET_free (gc->filename);
1039 GNUNET_free (gc);
1040 return NULL;
1041 }
1042 GNUNET_assert (GNUNET_OK ==
1043 GNUNET_DISK_pipe_close_end (gc->gnunet_rsa_out,
1044 GNUNET_DISK_PIPE_END_WRITE));
1045 gc->read_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
1046 GNUNET_DISK_pipe_handle (gc->gnunet_rsa_out,
1047 GNUNET_DISK_PIPE_END_READ),
1048 &check_key_generation_completion,
1049 gc);
1050 return gc;
1051}
1052
1053
1054/**
1055 * Abort RSA key generation.
1056 *
1057 * @param gc key generation context to abort
1058 */
1059void
1060GNUNET_CRYPTO_rsa_key_create_stop (struct GNUNET_CRYPTO_RsaKeyGenerationContext *gc)
1061{
1062 GNUNET_SCHEDULER_cancel (gc->read_task);
1063 if (NULL != gc->gnunet_rsa)
1064 {
1065 (void) GNUNET_OS_process_kill (gc->gnunet_rsa, SIGKILL);
1066 GNUNET_break (GNUNET_OK ==
1067 GNUNET_OS_process_wait (gc->gnunet_rsa));
1068 GNUNET_OS_process_destroy (gc->gnunet_rsa);
1069 }
1070 if (NULL != gc->filename)
1071 {
1072 if (0 != UNLINK (gc->filename))
1073 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", gc->filename);
1074 GNUNET_free (gc->filename);
1075 }
1076 if (NULL != gc->pk)
1077 GNUNET_CRYPTO_rsa_key_free (gc->pk);
1078 GNUNET_free (gc);
1079}
1080
1081
1082/**
789 * Setup a hostkey file for a peer given the name of the 1083 * Setup a hostkey file for a peer given the name of the
790 * configuration file (!). This function is used so that 1084 * configuration file (!). This function is used so that
791 * at a later point code can be certain that reading a 1085 * at a later point code can be certain that reading a