Thu, 20 Sep 2018 13:07:38 +0200
new secrets store file format
adds id and location fields for each entry
adds unencrypted index
dav/config.c | file | annotate | diff | comparison | revisions | |
dav/main.c | file | annotate | diff | comparison | revisions | |
dav/pwd.c | file | annotate | diff | comparison | revisions | |
dav/pwd.h | file | annotate | diff | comparison | revisions |
--- a/dav/config.c Sat Sep 15 11:58:17 2018 +0200 +++ b/dav/config.c Thu Sep 20 13:07:38 2018 +0200 @@ -103,7 +103,7 @@ repos = ucx_map_new(16); keys = ucx_map_new(16); - char *pwfile = util_concat_path(ENV_HOME, ".dav/pw.crypt"); + char *pwfile = util_concat_path(ENV_HOME, ".dav/secrets.crypt"); pstore = pwdstore_open(pwfile); free(pwfile); @@ -766,7 +766,7 @@ } int pwdstore_save(PwdStore *pwdstore) { - char *pwfile = util_concat_path(ENV_HOME, ".dav/pw.crypt"); + char *pwfile = util_concat_path(ENV_HOME, ".dav/secrets.crypt"); int ret = pwdstore_store(pwdstore, pwfile); free(pwfile); return ret;
--- a/dav/main.c Sat Sep 15 11:58:17 2018 +0200 +++ b/dav/main.c Thu Sep 20 13:07:38 2018 +0200 @@ -404,32 +404,61 @@ } } + +static int get_stored_credentials(CmdArgs *a, char *credid, char **user, char **password) { + if(!credid) { + return 0; + } + + PwdStore *secrets = get_pwdstore(); + if(!secrets) { + fprintf(stderr, "Error: no secrets store available\n"); + return 0; + } + + if(pwdstore_has_id(secrets, credid)) { + if(!secrets->isdecrypted) { + if(cmd_getoption(a, "noinput")) { + return 0; + } + char *ps_password = util_password_input("Master password: "); + if(!ps_password) { + return 0; + } + if(pwdstore_setpassword(secrets, ps_password)) { + fprintf(stderr, "Error: cannot create key from password\n"); + return 0; + } + if(pwdstore_decrypt(secrets)) { + fprintf(stderr, "Error: cannot decrypt secrets store\n"); + return 0; + } + } + + PwdEntry *s_cred = pwdstore_get(secrets, credid); + if(s_cred) { + *user = s_cred->user; + *password = s_cred->password; + return 1; + } + } else { + fprintf(stderr, "Error: credentials id '%s' not found\n", credid); + } + + return 0; +} + +static int get_location_credentials(CmdArgs *a, Repository *repo, char **user, char **password) { + return 0; +} + static DavSession* connect_to_repo(Repository *repo, CmdArgs *a) { char *user = repo->user; char *password = repo->password; - if(repo->stored_user && !cmd_getoption(a, "noinput")) { - PwdStore *pstore = get_pwdstore(); - if(pstore) { - char *ps_password = util_password_input("Unlock password store: "); - if(ps_password) { - if(!pwdstore_setpassword(pstore, ps_password)) { - if(!pwdstore_decrypt(pstore)) { - PwdEntry *stored_user = pwdstore_get(pstore, repo->stored_user); - if(stored_user) { - user = stored_user->user; - password = stored_user->password; - } else { - fprintf(stderr, "Error: stored user '%s' not found\n", repo->stored_user); - } - } else { - fprintf(stderr, "Error: cannot decrypt password store\n"); - } - } else { - fprintf(stderr, "Error: cannot create key from password\n"); - } - } - } else { - fprintf(stderr, "Error: no password store available\n"); + + if(!user && !password) { + if(!get_stored_credentials(a, repo->stored_user, &user, &password)) { + get_location_credentials(a, repo, &user, &password); } } @@ -2063,6 +2092,8 @@ } int cmd_add_user(CmdArgs *args) { + char *id = assistant_getcfg("Credentials identifier"); + char *user = assistant_getcfg("User"); char *password = util_password_input("Password: "); if(user && password) { @@ -2070,7 +2101,7 @@ if(!pstore) { pstore = pwdstore_new(); } - pwdstore_put(pstore, user, password); + pwdstore_put(pstore, id, NULL, user, password); char *master_pw = util_password_input("Master password: "); if(!master_pw) { return 1;
--- a/dav/pwd.c Sat Sep 15 11:58:17 2018 +0200 +++ b/dav/pwd.c Thu Sep 20 13:07:38 2018 +0200 @@ -54,17 +54,24 @@ } PwdStore *p = malloc(sizeof(PwdStore)); - p->pwds = ucx_map_new(16); + p->ids = ucx_map_new(16); + p->locations = NULL; p->content = buf; p->key = NULL; + p->encoffset = PWDS_HEADER_SIZE; p->isdecrypted = 0; + if(pwdstore_getindex(p)) { + pwdstore_free(p); + return NULL; + } + return p; } PwdStore* pwdstore_new(void) { PwdStore *p = calloc(1, sizeof(PwdStore)); - p->pwds = ucx_map_new(16); + p->ids = ucx_map_new(16); p->content = ucx_buffer_new(NULL, PWDS_HEADER_SIZE, UCX_BUFFER_AUTOEXTEND); PWDS_MAGIC(p) = PWDS_MAGIC_CHAR; PWDS_VERSION(p) = 1; @@ -74,51 +81,86 @@ return p; } -static int read_pwdentry(PwdStore *p, UcxBuffer *in) { +static int readval(UcxBuffer *in, char **val, int allowzero) { + *val = NULL; + uint32_t length = 0; + if(ucx_buffer_read(&length, 1, sizeof(uint32_t), in) != sizeof(uint32_t)) { + return 0; + } + length = ntohl(length); + if((length == 0 && !allowzero) || length > PWDSTORE_MAX_LEN) { + return 0; + } + + char *value = malloc(length + 1); + value[length] = 0; + if(ucx_buffer_read(value, 1, length, in) != length) { + free(value); + return 0; + } + + *val = value; + return 1; +} + +static int read_pwdentry(PwdStore *p, UcxBuffer *in, int index) { int type = ucx_buffer_getc(in); if(type == EOF || type != 0) { // only type 0 supported yet return 0; } - uint32_t ulen = 0; - uint32_t plen = 0; + char *id = NULL; + char *location = NULL; + char *user = NULL; + char *password = NULL; - if(ucx_buffer_read(&ulen, 1, sizeof(uint32_t), in) != sizeof(uint32_t)) { - return 0; - } - ulen = ntohl(ulen); - if(ulen == 0 || ulen > PWDSTORE_MAX_LEN) { - return 0; + int res = 0; + if((res += readval(in, &id, FALSE)) == 1) { + if((res += readval(in, &location, TRUE)) == 2) { + if((res += readval(in, &user, FALSE)) == 3) { + res += readval(in, &password, FALSE); + } + } } - char *user = malloc(ulen+1); - user[ulen] = 0; - if(ucx_buffer_read(user, 1, ulen, in) != ulen) { - free(user); - return 0; + int ret = 0; + if((!index && res == 4) || (index && res == 2)) { + pwdstore_put(p, id, location, user, password); + ret = 1; } - if(ucx_buffer_read(&plen, 1, sizeof(uint32_t), in) != sizeof(uint32_t)) { - return 0; - } - plen = ntohl(plen); - if(plen == 0 || plen > PWDSTORE_MAX_LEN) { - return 0; + if(id) free(id); + if(location) free(location); + if(user) free(user); + if(password) free(password); + + return ret; + +} + +int pwdstore_getindex(PwdStore *s) { + uint32_t netindexlen; + s->content->pos = PWDS_HEADER_SIZE - sizeof(uint32_t); + if(ucx_buffer_read(&netindexlen, 1, sizeof(uint32_t), s->content) != sizeof(uint32_t)) { + return 1; } - char *password = malloc(plen+1); - password[plen] = 0; - if(ucx_buffer_read(password, 1, plen, in) != plen) { - free(user); - free(password); - return 0; + uint32_t indexlen = ntohl(netindexlen); + if(UINT32_MAX - PWDS_HEADER_SIZE < indexlen) { + return 1; + } + if(s->content->size < PWDS_HEADER_SIZE + indexlen) { + return 1; } + s->encoffset += indexlen; - pwdstore_put(p, user, password); - free(user); - free(password); - return 1; + UcxBuffer *index = ucx_buffer_new(s->content->space+PWDS_HEADER_SIZE, indexlen, 0); + index->size = indexlen; + while(read_pwdentry(s, index, 1)) {} + ucx_buffer_free(index); + + return 0; } int pwdstore_decrypt(PwdStore *p) { @@ -127,17 +169,17 @@ } // decrypt contet - size_t encsz = p->content->size - PWDS_HEADER_SIZE; - UcxBuffer *enc = ucx_buffer_new(p->content->space + PWDS_HEADER_SIZE, encsz, 0); + size_t encsz = p->content->size - p->encoffset; + UcxBuffer *enc = ucx_buffer_new(p->content->space + p->encoffset, encsz, 0); enc->size = encsz; - enc->size = p->content->size - PWDS_HEADER_SIZE; + enc->size = p->content->size - p->encoffset; UcxBuffer *content = aes_decrypt_buffer(enc, p->key); ucx_buffer_free(enc); if(!content) { return 1; } - while(read_pwdentry(p, content)) {} + while(read_pwdentry(p, content, 0)) {} ucx_buffer_free(content); @@ -165,14 +207,18 @@ } static void free_entry(PwdEntry *e) { - free(e->user); - free(e->password); + if(e->id) free(e->id); + if(e->location) free(e->location); + if(e->user) free(e->user); + if(e->password) free(e->password); free(e); } void pwdstore_free(PwdStore* p) { - ucx_map_free_content(p->pwds, (ucx_destructor)free_entry); - ucx_map_free(p->pwds); + ucx_map_free_content(p->ids, (ucx_destructor)free_entry); + ucx_map_free(p->ids); + + ucx_list_free(p->locations); if(p->content) { ucx_buffer_free(p->content); @@ -181,15 +227,34 @@ free(p); } -PwdEntry* pwdstore_get(PwdStore *p, const char *username) { - return ucx_map_cstr_get(p->pwds, username); +int pwdstore_has_id(PwdStore *s, const char *id) { + return ucx_map_cstr_get(s->ids, id) ? 1 : 0; +} + +int pwdstore_has_location(PwdStore *s, const char *location) { + return 0; } -void pwdstore_put(PwdStore *p, const char *username, const char *password) { +PwdEntry* pwdstore_get(PwdStore *p, const char *id) { + PwdEntry *e = ucx_map_cstr_get(p->ids, id); + if(e->user && e->password) { + return e; + } else { + return NULL; + } +} + +void pwdstore_put(PwdStore *p, const char *id, const char *location, const char *username, const char *password) { PwdEntry *entry = malloc(sizeof(PwdEntry)); - entry->user = strdup(username); - entry->password = strdup(password); - ucx_map_cstr_put(p->pwds, entry->user, entry); + entry->id = strdup(id); + entry->location = location ? strdup(location) : NULL; + entry->user = username ? strdup(username) : NULL; + entry->password = password ? strdup(password) : NULL; + ucx_map_cstr_put(p->ids, id, entry); + + if(location) { + p->locations = ucx_list_append(p->locations, entry); + } } int pwdstore_store(PwdStore *p, const char *file) { @@ -197,27 +262,58 @@ return 1; } + UcxBuffer *index = ucx_buffer_new(NULL, 2048, UCX_BUFFER_AUTOEXTEND); UcxBuffer *content = ucx_buffer_new(NULL, 2048, UCX_BUFFER_AUTOEXTEND); - UcxMapIterator i = ucx_map_iterator(p->pwds); + UcxMapIterator i = ucx_map_iterator(p->ids); PwdEntry *value; UCX_MAP_FOREACH(key, value, i) { - ucx_buffer_putc(content, 0); // type + uint32_t idlen = strlen(value->id); + uint32_t locationlen = value->location ? strlen(value->location) : 0; uint32_t ulen = strlen(value->user); uint32_t plen = strlen(value->password); + uint32_t netidlen = htonl(idlen); + uint32_t netlocationlen = htonl(locationlen); uint32_t netulen = htonl(ulen); uint32_t netplen = htonl(plen); + + // index buffer + ucx_buffer_putc(index, 0); // type + + ucx_buffer_write(&netidlen, 1, sizeof(uint32_t), index); + ucx_buffer_write(value->id, 1, idlen, index); + ucx_buffer_write(&netlocationlen, 1, sizeof(uint32_t), index); + if(value->location) { + ucx_buffer_write(value->location, 1, locationlen, index); + } + + // content buffer + ucx_buffer_putc(content, 0); // type + + ucx_buffer_write(&netidlen, 1, sizeof(uint32_t), content); + ucx_buffer_write(value->id, 1, idlen, content); + ucx_buffer_write(&netlocationlen, 1, sizeof(uint32_t), content); + if(value->location) { + ucx_buffer_write(value->location, 1, locationlen, content); + } ucx_buffer_write(&netulen, 1, sizeof(uint32_t), content); ucx_buffer_write(value->user, 1, ulen, content); ucx_buffer_write(&netplen, 1, sizeof(uint32_t), content); ucx_buffer_write(value->password, 1, plen, content); } - + content->pos = 0; UcxBuffer *enc = aes_encrypt_buffer(content, p->key); - p->content->pos = PWDS_HEADER_SIZE; + p->content->pos = PWDS_HEADER_SIZE - sizeof(uint32_t); p->content->size = PWDS_HEADER_SIZE; + + // add index after header + uint32_t netindexlen = htonl((uint32_t)index->size); + ucx_buffer_write(&netindexlen, 1, sizeof(uint32_t), p->content); + ucx_buffer_write(index->space, 1, index->size, p->content); + + // add encrypted buffer ucx_buffer_write(enc->space, 1, enc->size, p->content); ucx_buffer_free(enc);
--- a/dav/pwd.h Sat Sep 15 11:58:17 2018 +0200 +++ b/dav/pwd.h Thu Sep 20 13:07:38 2018 +0200 @@ -40,21 +40,24 @@ extern "C" { #endif -#define PWDSTORE_MAX_LEN 1024 +#define PWDSTORE_MAX_LEN 4096 /* * File Format: * * file = header, enc_content - * header = magic, version, enc, pwfunc, salt + * header = magic, version, enc, pwfunc, salt, indexlen * magic = 1 byte * version = 1 byte * enc = 1 byte * pwfunc = 1 byte * salt = 16 bytes + * indexlen = uint32 * content = { entry } - * entry = length username length password - * length = uint16 + * entry = length id length location length username length password + * length = uint32 + * id = string + * location = string * username = string * password = string * @@ -64,18 +67,24 @@ * All integers are big endian */ -#define PWDS_HEADER_SIZE 20 +#define PWDS_HEADER_SIZE 24 typedef struct PwdStore PwdStore; typedef struct PwdEntry PwdEntry; struct PwdStore { /* - * map of all usernames and passwords + * map of all credentials * key is the username * value is PwdEntry* */ - UcxMap *pwds; + UcxMap *ids; + + /* + * list of all credentials with location + * value is PwdEntry* + */ + UcxList *locations; /* * a buffer containing the complete file content @@ -88,6 +97,11 @@ DavKey *key; /* + * start offset of the encrypted buffer + */ + uint32_t encoffset; + + /* * indicates if the PwdStore is decrypted with pwdstore_decrypt */ uint8_t isdecrypted; @@ -101,6 +115,8 @@ #define PWDS_MAGIC_CHAR 'P' struct PwdEntry { + char *id; + char *location; char *user; char *password; }; @@ -124,12 +140,18 @@ void pwdstore_free(PwdStore* p); -PwdEntry* pwdstore_get(PwdStore *p, const char *username); +int pwdstore_has_id(PwdStore *s, const char *id); +int pwdstore_has_location(PwdStore *s, const char *location); -void pwdstore_put(PwdStore *p, const char *username, const char *password); +PwdEntry* pwdstore_get(PwdStore *p, const char *id); + +void pwdstore_put(PwdStore *p, const char *id, const char *location, const char *username, const char *password); int pwdstore_store(PwdStore *p, const char *file); +/* private */ +int pwdstore_getindex(PwdStore *s); + #ifdef __cplusplus } #endif