serval-dna/keyring.c

208 lines
5.4 KiB
C

/*
Copyright (C) 2010-2012 Paul Gardner-Stephen, Serval Project.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "serval.h"
/*
Open keyring file, read BAM and create initial context using the
stored salt. */
keyring_file *keyring_open(char *file)
{
/* Allocate structure */
keyring_file *k=calloc(sizeof(keyring_file),1);
if (!k) { WHY("calloc() failed"); return NULL; }
/* Open keyring file read-write if we can, else use it read-only */
k->file=fopen(file,"r+");
if (!k->file) k->file=fopen(file,"r");
if (!k->file) {
WHY("Could not open keyring file");
keyring_free(k);
return NULL;
}
if (fseeko(k->file,0,SEEK_END))
{
WHY("Could not seek to end of keyring file");
keyring_free(k);
return NULL;
}
k->file_size=ftello(k->file);
/* Read BAMs for each slab in the file */
keyring_bam **b=&k->bam;
off_t offset=0;
while(offset<k->file_size) {
/* Read bitmap from slab.
Also, if offset is zero, read the salt */
if (fseeko(k->file,offset,SEEK_SET))
{
WHY("Could not seek to BAM in keyring file");
keyring_free(k);
return NULL;
}
*b=calloc(sizeof(keyring_bam),1);
if (!(*b))
{
WHY("Could not allocate keyring_bam structure for key ring file");
keyring_free(k);
return NULL;
}
(*b)->file_offset=offset;
/* Read bitmap */
int r=fread(&(*b)->bitmap[0],KEYRING_BAM_BYTES,1,k->file);
if (r!=1)
{
WHY("Could not read BAM from keyring file");
keyring_free(k);
return NULL;
}
/* Read salt if this is the first bitmap block.
We setup a context for this self-supplied key-ring salt.
(other keyring salts may be provided later on, resulting in
multiple contexts being loaded) */
if (!offset) {
k->contexts[0]=calloc(sizeof(keyring_context),1);
if (!k->contexts[0])
{
WHY("Could not allocate keyring_context for keyring file");
keyring_free(k);
return NULL;
}
k->contexts[0]->KeyRingSaltLen=KEYRING_PAGE_SIZE-KEYRING_BAM_BYTES;
k->contexts[0]->KeyRingSalt=malloc(k->contexts[0]->KeyRingSaltLen);
if (!k->contexts[0]->KeyRingSalt)
{
WHY("Could not allocate keyring_context->salt for keyring file");
keyring_free(k);
return NULL;
}
r=fread(&k->contexts[0]->KeyRingSalt[0],k->contexts[0]->KeyRingSaltLen,1,k->file);
if (r!=1)
{
WHY("Could not read salt from keyring file");
keyring_free(k);
return NULL;
}
k->context_count=1;
}
/* Skip to next slab, and find next bam pointer. */
offset+=KEYRING_PAGE_SIZE*(KEYRING_BAM_BYTES<<3);
b=&(*b)->next;
}
return k;
}
void keyring_free(keyring_file *k)
{
int i;
if (!k) return;
/* Close keyring file handle */
if (k->file) fclose(k->file);
k->file=NULL;
/* Free BAMs (no substructure, so easy) */
keyring_bam *b=k->bam;
while(b) {
keyring_bam *last_bam=b;
b=b->next;
/* Clear out any private data */
bzero(last_bam,sizeof(keyring_bam));
/* release structure */
free(last_bam);
}
/* Free contexts (including subordinate identities and dynamically allocated salt strings).
Don't forget to overwrite any private data. */
for(i=0;i<KEYRING_MAX_CONTEXTS;i++)
if (k->contexts[i]) {
keyring_free_context(k->contexts[i]);
k->contexts[i]=NULL;
}
/* Wipe everything, just to be sure. */
bzero(k,sizeof(keyring_file));
return;
}
void keyring_free_context(keyring_context *c)
{
int i;
if (!c) return;
if (c->KeyRingPin) {
/* Wipe pin before freeing (slightly tricky since this is a variable length string */
for(i=0;c->KeyRingPin[i];i++) c->KeyRingPin[i]=' '; i=0;
free(c->KeyRingPin); c->KeyRingPin=NULL;
}
if (c->KeyRingSalt) {
bzero(c->KeyRingSalt,c->KeyRingSaltLen);
c->KeyRingSalt=NULL;
c->KeyRingSaltLen=0;
}
/* Wipe out any loaded identities */
for(i=0;i<KEYRING_MAX_IDENTITIES;i++)
if (c->identities[i]) keyring_free_identity(c->identities[i]);
/* Make sure any private data is wiped out */
bzero(c,sizeof(keyring_context));
return;
}
void keyring_free_identity(keyring_identity *id)
{
int i;
if (id->PKRPin) {
/* Wipe pin before freeing (slightly tricky since this is a variable length string */
for(i=0;id->PKRPin[i];i++) id->PKRPin[i]=' '; i=0;
free(id->PKRPin); id->PKRPin=NULL;
}
for(i=0;i<PKR_MAX_KEYPAIRS;i++)
if (id->keypairs[i])
keyring_free_keypair(id->keypairs[i]);
bzero(id,sizeof(keyring_identity));
return;
}
void keyring_free_keypair(keypair *kp)
{
if (kp->private_key) {
bzero(kp->private_key,kp->private_key_len);
free(kp->private_key);
kp->private_key=NULL;
}
if (kp->public_key) {
bzero(kp->public_key,kp->public_key_len);
free(kp->public_key);
kp->public_key=NULL;
}
bzero(kp,sizeof(keypair));
return;
}