// maximilian.kaul@aisec.fraunhofer.de // WIP implementation of // https://github.com/ontio/ontology-crypto/wiki/Anonymous-Credential // using the relic library https://github.com/relic-toolkit/relic/ #include "pabc_helper.h" #include #include #include static char pabc_dir[PATH_MAX + 1]; static const char * get_homedir () { const char *homedir; if ((homedir = getenv ("HOME")) == NULL) { homedir = getpwuid (getuid ())->pw_dir; } return homedir; } static enum GNUNET_GenericReturnValue write_file (char const *const filename, const char *buffer) { struct GNUNET_DISK_FileHandle *fh; fh = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_TRUNCATE | GNUNET_DISK_OPEN_CREATE, GNUNET_DISK_PERM_USER_WRITE | GNUNET_DISK_PERM_USER_READ); if (fh == NULL) return GNUNET_SYSERR; if (GNUNET_SYSERR == GNUNET_DISK_file_write (fh, buffer, strlen (buffer) + 1)) goto fail; GNUNET_DISK_file_close (fh); return GNUNET_OK; fail: GNUNET_DISK_file_close (fh); return GNUNET_SYSERR; } static enum GNUNET_GenericReturnValue init_pabc_dir () { size_t filename_size = strlen (get_homedir ()) + 1 + strlen (".local") + 1 + strlen ("pabc-reclaim") + 1; snprintf (pabc_dir, filename_size, "%s/%s/%s", get_homedir (), ".local", "pabc-reclaim"); return GNUNET_DISK_directory_create (pabc_dir); } static const char * get_pabcdir () { init_pabc_dir (); return pabc_dir; } enum GNUNET_GenericReturnValue read_file (char const *const filename, char **buffer) { struct GNUNET_DISK_FileHandle *fh; if (GNUNET_YES != GNUNET_DISK_file_test (filename)) return GNUNET_SYSERR; fh = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_USER_READ); if (fh == NULL) return GNUNET_SYSERR; long lSize = GNUNET_DISK_file_seek (fh, 0, GNUNET_DISK_SEEK_END); if (lSize < 0) goto fail; GNUNET_DISK_file_seek (fh, 0, GNUNET_DISK_SEEK_SET); *buffer = calloc ((size_t) lSize + 1, sizeof(char)); if (*buffer == NULL) goto fail; // copy the file into the buffer: size_t r = GNUNET_DISK_file_read (fh, *buffer, (size_t) lSize); if (r != (size_t) lSize) goto fail; GNUNET_DISK_file_close (fh); return GNUNET_OK; fail: GNUNET_DISK_file_close (fh); return GNUNET_SYSERR; } struct pabc_public_parameters * PABC_read_issuer_ppfile (const char *f, struct pabc_context *const ctx) { if (NULL == ctx) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No global context provided\n"); return NULL; } struct pabc_public_parameters *pp; char *buffer; int r; r = read_file (f, &buffer); if (GNUNET_OK != r) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error reading file\n"); return NULL; } if (PABC_OK != pabc_decode_and_new_public_parameters (ctx, &pp, buffer)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to decode public parameters\n"); PABC_FREE_NULL (buffer); return NULL; } PABC_FREE_NULL (buffer); return pp; } enum GNUNET_GenericReturnValue PABC_load_public_parameters (struct pabc_context *const ctx, char const *const pp_name, struct pabc_public_parameters **pp) { char fname[PATH_MAX]; char *pp_filename; const char *pdir = get_pabcdir (); if (ctx == NULL) return GNUNET_SYSERR; if (pp_name == NULL) return GNUNET_SYSERR; GNUNET_STRINGS_urlencode (pp_name, strlen (pp_name), &pp_filename); if (GNUNET_YES != GNUNET_DISK_directory_test (pdir, GNUNET_YES)) { GNUNET_free (pp_filename); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error reading %s\n", pdir); return GNUNET_SYSERR; } snprintf (fname, PATH_MAX, "%s/%s%s", pdir, pp_filename, PABC_PP_EXT); if (GNUNET_YES != GNUNET_DISK_file_test (fname)) { GNUNET_free (pp_filename); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error testing %s\n", fname); return GNUNET_SYSERR; } *pp = PABC_read_issuer_ppfile (fname, ctx); if (*pp) return GNUNET_OK; else return GNUNET_SYSERR; } enum GNUNET_GenericReturnValue PABC_write_public_parameters (char const *const pp_name, struct pabc_public_parameters *const pp) { char *json; char *filename; char *pp_filename; enum pabc_status status; struct pabc_context *ctx = NULL; GNUNET_STRINGS_urlencode (pp_name, strlen (pp_name), &pp_filename); PABC_ASSERT (pabc_new_ctx (&ctx)); // store in json file status = pabc_encode_public_parameters (ctx, pp, &json); if (status != PABC_OK) { GNUNET_free (pp_filename); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to encode public parameters.\n"); pabc_free_ctx (&ctx); return GNUNET_SYSERR; } size_t filename_size = strlen (get_pabcdir ()) + 1 + strlen (pp_filename) + strlen (PABC_PP_EXT) + 1; filename = GNUNET_malloc (filename_size); if (! filename) { GNUNET_free (pp_filename); PABC_FREE_NULL (json); pabc_free_ctx (&ctx); return GNUNET_SYSERR; } snprintf (filename, filename_size, "%s/%s%s", get_pabcdir (), pp_filename, PABC_PP_EXT); GNUNET_free (pp_filename); if (GNUNET_OK != write_file (filename, json)) { PABC_FREE_NULL (filename); PABC_FREE_NULL (json); pabc_free_ctx (&ctx); return GNUNET_SYSERR; } PABC_FREE_NULL (filename); PABC_FREE_NULL (json); pabc_free_ctx (&ctx); return GNUNET_OK; } enum GNUNET_GenericReturnValue PABC_write_usr_ctx (char const *const usr_name, char const *const pp_name, struct pabc_context const *const ctx, struct pabc_public_parameters const *const pp, struct pabc_user_context *const usr_ctx) { char *pp_filename; char *json = NULL; enum pabc_status status; char *fname = NULL; if (NULL == usr_name) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No issuer given.\n"); return GNUNET_SYSERR; } if (NULL == pp_name) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No user given.\n"); return GNUNET_SYSERR; } if (NULL == ctx) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No context given.\n"); return GNUNET_SYSERR; } if (NULL == pp) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No public parameters given.\n"); return GNUNET_SYSERR; } if (NULL == usr_ctx) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No user context given.\n"); return GNUNET_SYSERR; } GNUNET_STRINGS_urlencode (pp_name, strlen (pp_name), &pp_filename); status = pabc_encode_user_ctx (ctx, pp, usr_ctx, &json); if (PABC_OK != status) { GNUNET_free (pp_filename); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to encode user context.\n"); return status; } size_t fname_size = strlen (get_pabcdir ()) + 1 + strlen (usr_name) + 1 + strlen (pp_filename) + strlen (PABC_USR_EXT) + 1; fname = GNUNET_malloc (fname_size); snprintf (fname, fname_size, "%s/%s_%s%s", get_pabcdir (), usr_name, pp_filename, PABC_USR_EXT); GNUNET_free (pp_filename); if (GNUNET_OK == write_file (fname, json)) { GNUNET_free (fname); GNUNET_free (json); return GNUNET_OK; } else { GNUNET_free (fname); GNUNET_free (json); return GNUNET_SYSERR; } } enum GNUNET_GenericReturnValue PABC_read_usr_ctx (char const *const usr_name, char const *const pp_name, struct pabc_context const *const ctx, struct pabc_public_parameters const *const pp, struct pabc_user_context **usr_ctx) { char *json = NULL; char *pp_filename; enum pabc_status status; char *fname = NULL; if (NULL == usr_name) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No issuer given.\n"); return GNUNET_SYSERR; } if (NULL == pp_name) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No user given.\n"); return GNUNET_SYSERR; } if (NULL == ctx) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No context given.\n"); return GNUNET_SYSERR; } if (NULL == pp) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No public parameters given.\n"); return GNUNET_SYSERR; } if (NULL == usr_ctx) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No user context given.\n"); return GNUNET_SYSERR; } GNUNET_STRINGS_urlencode (pp_name, strlen (pp_name), &pp_filename); size_t fname_size = strlen (get_pabcdir ()) + 1 + strlen (usr_name) + 1 + strlen (pp_filename) + strlen (PABC_USR_EXT) + 1; fname = GNUNET_malloc (fname_size); snprintf (fname, fname_size, "%s/%s_%s%s", get_pabcdir (), usr_name, pp_filename, PABC_USR_EXT); GNUNET_free (pp_filename); if (GNUNET_OK != read_file (fname, &json)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to read `%s'\n", fname); PABC_FREE_NULL (fname); return GNUNET_SYSERR; } GNUNET_free (fname); status = pabc_new_user_context (ctx, pp, usr_ctx); if (PABC_OK != status) { GNUNET_free (json); return GNUNET_SYSERR; } status = pabc_decode_user_ctx (ctx, pp, *usr_ctx, json); GNUNET_free (json); if (PABC_OK != status) { pabc_free_user_context (ctx, pp, usr_ctx); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to encode user context.\n"); return GNUNET_SYSERR; } return GNUNET_OK; }