2012-04-10 03:25:46 +00:00
/*
2013-11-21 02:12:59 +00:00
Serval DNA keyring
2013-12-04 06:26:55 +00:00
Copyright ( C ) 2013 Serval Project Inc .
2013-11-21 02:12:59 +00:00
Copyright ( C ) 2010 - 2012 Paul Gardner - Stephen
2012-04-10 03:25:46 +00:00
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 .
*/
2013-04-29 05:01:50 +00:00
# include <stdio.h>
2013-03-06 04:13:52 +00:00
# include <assert.h>
2012-04-10 03:25:46 +00:00
# include "serval.h"
2012-10-18 05:16:16 +00:00
# include "rhizome.h"
2014-07-23 01:03:41 +00:00
# include "conf.h"
# include "constants.h"
2012-04-10 21:20:57 +00:00
# include "nacl.h"
2012-08-27 00:34:59 +00:00
# include "overlay_address.h"
2013-10-14 03:58:48 +00:00
# include "crypto.h"
2013-12-09 07:15:47 +00:00
# include "overlay_interface.h"
2013-10-14 03:58:48 +00:00
# include "overlay_packet.h"
2014-02-03 01:41:56 +00:00
# include "overlay_buffer.h"
2013-10-16 03:00:00 +00:00
# include "keyring.h"
2013-11-25 02:39:54 +00:00
# include "dataformats.h"
2014-07-23 01:03:41 +00:00
# include "str.h"
# include "mem.h"
# include "rotbuf.h"
2014-08-25 04:54:00 +00:00
# include "server.h"
2015-08-31 05:48:08 +00:00
# include "route_link.h"
2012-04-10 03:25:46 +00:00
2015-02-23 02:54:05 +00:00
static keyring_file * keyring_open_or_create ( const char * path , int writeable ) ;
static int keyring_initialise ( keyring_file * k ) ;
static int keyring_load ( keyring_file * k , const char * pin ) ;
static keyring_file * keyring_open_create_instance ( const char * pin , int force_create ) ;
2013-09-02 08:03:52 +00:00
static void keyring_free_keypair ( keypair * kp ) ;
2013-10-10 03:52:20 +00:00
static void keyring_free_identity ( keyring_identity * id ) ;
2013-09-05 07:04:01 +00:00
static int keyring_identity_mac ( const keyring_identity * id , unsigned char * pkrsalt , unsigned char * mac ) ;
2013-09-02 08:03:52 +00:00
2013-08-29 08:03:39 +00:00
static int _keyring_open ( keyring_file * k , const char * path , const char * mode )
{
2015-07-06 08:19:49 +00:00
DEBUGF ( keyring , " opening %s in \" %s \" mode " , alloca_str_toprint ( path ) , mode ) ;
2013-08-29 08:03:39 +00:00
k - > file = fopen ( path , mode ) ;
if ( ! k - > file ) {
if ( errno ! = EPERM & & errno ! = ENOENT )
return WHYF_perror ( " fopen(%s, \" %s \" ) " , alloca_str_toprint(path), mode) ;
2015-07-06 08:19:49 +00:00
DEBUGF ( keyring , " cannot open %s in \" %s \" mode " , alloca_str_toprint ( path ) , mode ) ;
2013-08-29 08:03:39 +00:00
}
return 0 ;
}
2012-04-10 03:25:46 +00:00
/*
2015-02-23 02:54:05 +00:00
* Open keyring file and detect its size .
2013-08-29 08:03:39 +00:00
*/
2015-02-23 02:54:05 +00:00
static keyring_file * keyring_open_or_create ( const char * path , int writeable )
2012-04-10 03:25:46 +00:00
{
/* Allocate structure */
2013-03-06 04:13:52 +00:00
keyring_file * k = emalloc_zero ( sizeof ( keyring_file ) ) ;
if ( ! k )
2012-05-19 01:08:29 +00:00
return NULL ;
2013-08-29 08:03:39 +00:00
/* Open keyring file read-write if we can, else use it read-only, else create it. */
if ( writeable & & _keyring_open ( k , path , " r+ " ) = = - 1 ) {
keyring_free ( k ) ;
return NULL ;
}
if ( ! k - > file & & _keyring_open ( k , path , " r " ) = = - 1 ) {
keyring_free ( k ) ;
return NULL ;
}
if ( ! k - > file & & writeable & & _keyring_open ( k , path , " w+ " ) = = - 1 ) {
keyring_free ( k ) ;
return NULL ;
}
2012-04-10 03:25:46 +00:00
if ( ! k - > file ) {
2013-08-29 08:03:39 +00:00
WHYF_perror ( " cannot open or create keyring file %s " , alloca_str_toprint ( path ) ) ;
keyring_free ( k ) ;
return NULL ;
2012-05-19 01:08:29 +00:00
}
2013-03-06 04:13:52 +00:00
if ( fseeko ( k - > file , 0 , SEEK_END ) ) {
2013-04-30 07:59:06 +00:00
WHYF_perror ( " fseeko(%s, 0, SEEK_END) " , alloca_str_toprint ( path ) ) ;
2012-04-10 03:25:46 +00:00
keyring_free ( k ) ;
return NULL ;
}
2015-02-23 02:54:05 +00:00
k - > file_size = ftello ( k - > file ) ;
return k ;
}
2012-04-10 04:19:18 +00:00
2015-02-23 02:54:05 +00:00
/*
* Write initial content of keyring file ( erasing anything already there ) .
*/
static int keyring_initialise ( keyring_file * k )
{
// Write 2KB of zeroes, followed by 2KB of random bytes as salt.
if ( fseeko ( k - > file , 0 , SEEK_SET ) )
return WHYF_perror ( " fseeko(%d, 0, SEEK_SET) " , fileno(k->file)) ;
unsigned char buffer [ KEYRING_PAGE_SIZE ] ;
bzero ( & buffer [ 0 ] , KEYRING_BAM_BYTES ) ;
if ( urandombytes ( & buffer [ KEYRING_BAM_BYTES ] , KEYRING_PAGE_SIZE - KEYRING_BAM_BYTES ) )
return WHYF ( " Could not generate random keyring salt " ) ;
if ( fwrite ( buffer , KEYRING_PAGE_SIZE , 1 , k - > file ) ! = 1 ) {
WHYF_perror ( " fwrite(%p, %zu, 1, %d) " , buffer , KEYRING_PAGE_SIZE - KEYRING_BAM_BYTES , fileno ( k - > file ) ) ;
return WHYF ( " Could not write page into keyring file " ) ;
}
k - > file_size = KEYRING_PAGE_SIZE ;
return 0 ;
}
/*
* Read the BAM and create initial context using the stored salt .
*/
static int keyring_load ( keyring_file * k , const char * pin )
{
2012-04-10 03:25:46 +00:00
/* Read BAMs for each slab in the file */
keyring_bam * * b = & k - > bam ;
2015-02-23 02:54:05 +00:00
size_t offset = 0 ;
while ( offset < k - > file_size ) {
/* Read bitmap from slab. If offset is zero, read the salt */
if ( fseeko ( k - > file , ( off_t ) offset , SEEK_SET ) ) {
WHYF_perror ( " fseeko(%d, %zd, SEEK_SET) " , fileno ( k - > file ) , offset ) ;
return WHY ( " Could not seek to BAM in keyring file " ) ;
2012-05-19 01:08:29 +00:00
}
2013-03-06 04:13:52 +00:00
* b = emalloc_zero ( sizeof ( keyring_bam ) ) ;
2015-02-23 02:54:05 +00:00
if ( ! * b )
return WHYF ( " Could not allocate keyring_bam structure " ) ;
( * b ) - > file_offset = offset ;
2012-04-10 03:25:46 +00:00
/* Read bitmap */
2015-02-23 02:54:05 +00:00
int r = fread ( ( * b ) - > bitmap , KEYRING_BAM_BYTES , 1 , k - > file ) ;
if ( r ! = 1 ) {
WHYF_perror ( " fread(%p, %zd, 1, %d) " , ( * b ) - > bitmap , KEYRING_BAM_BYTES , fileno ( k - > file ) ) ;
return WHYF ( " Could not read BAM from keyring file " ) ;
2012-05-19 01:08:29 +00:00
}
2012-04-10 03:25:46 +00:00
/* 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
2012-04-12 04:30:51 +00:00
multiple contexts being loaded ) */
2014-10-31 03:13:23 +00:00
if ( ! offset ) {
2014-10-31 04:30:52 +00:00
k - > KeyRingPin = str_edup ( pin ) ;
k - > KeyRingSaltLen = KEYRING_PAGE_SIZE - KEYRING_BAM_BYTES ;
k - > KeyRingSalt = emalloc ( k - > KeyRingSaltLen ) ;
2015-02-23 02:54:05 +00:00
if ( ! k - > KeyRingSalt )
return WHYF ( " Could not allocate keyring_context->salt " ) ;
2014-10-31 04:30:52 +00:00
r = fread ( k - > KeyRingSalt , k - > KeyRingSaltLen , 1 , k - > file ) ;
2012-05-19 01:08:29 +00:00
if ( r ! = 1 ) {
2015-02-23 02:54:05 +00:00
WHYF_perror ( " fread(%p, %d, 1, %d) " , k - > KeyRingSalt , k - > KeyRingSaltLen , fileno ( k - > file ) ) ;
return WHYF ( " Could not read salt from keyring file " ) ;
2012-05-19 01:08:29 +00:00
}
2012-04-10 03:25:46 +00:00
}
/* Skip to next slab, and find next bam pointer. */
2015-02-23 02:54:05 +00:00
offset + = KEYRING_PAGE_SIZE * ( KEYRING_BAM_BYTES < < 3 ) ;
b = & ( * b ) - > next ;
2012-04-10 03:25:46 +00:00
}
2015-02-23 02:54:05 +00:00
return 0 ;
2012-04-10 03:25:46 +00:00
}
2014-10-31 03:13:23 +00:00
void keyring_iterator_start ( keyring_file * k , keyring_iterator * it )
2013-09-04 14:17:17 +00:00
{
2014-10-31 03:13:23 +00:00
bzero ( it , sizeof ( keyring_iterator ) ) ;
assert ( k ) ;
it - > file = k ;
}
keyring_identity * keyring_next_identity ( keyring_iterator * it )
{
2014-10-31 04:30:52 +00:00
assert ( it - > file ) ;
if ( ! it - > identity )
it - > identity = it - > file - > identities ;
else
2014-10-31 03:13:23 +00:00
it - > identity = it - > identity - > next ;
if ( it - > identity )
it - > keypair = it - > identity - > keypairs ;
else
2014-10-31 04:30:52 +00:00
it - > keypair = NULL ;
2014-10-31 03:13:23 +00:00
return it - > identity ;
}
keypair * keyring_next_key ( keyring_iterator * it )
{
if ( it - > keypair )
it - > keypair = it - > keypair - > next ;
if ( ! it - > keypair )
keyring_next_identity ( it ) ;
return it - > keypair ;
}
keypair * keyring_next_keytype ( keyring_iterator * it , unsigned keytype )
{
keypair * kp ;
while ( ( kp = keyring_next_key ( it ) ) & & kp - > type ! = keytype )
;
return kp ;
}
keypair * keyring_identity_keytype ( keyring_identity * id , unsigned keytype )
{
keypair * kp = id - > keypairs ;
while ( kp & & kp - > type ! = keytype )
kp = kp - > next ;
return kp ;
}
# define find_keypair_sid(X) keyring_identity_keytype((X),KEYTYPE_CRYPTOBOX)
keypair * keyring_find_did ( keyring_iterator * it , const char * did )
{
keypair * kp ;
while ( ( kp = keyring_next_keytype ( it , KEYTYPE_DID ) ) ) {
if ( ( ! did [ 0 ] )
| | ( did [ 0 ] = = ' * ' & & did [ 1 ] = = 0 )
| | ( ! strcasecmp ( did , ( char * ) kp - > private_key ) )
) {
return kp ;
}
}
return NULL ;
}
keypair * keyring_find_sid ( keyring_iterator * it , const sid_t * sidp )
{
keypair * kp ;
while ( ( kp = keyring_next_keytype ( it , KEYTYPE_CRYPTOBOX ) ) ) {
if ( memcmp ( sidp - > binary , kp - > public_key , SID_SIZE ) = = 0 )
return kp ;
}
return NULL ;
}
static void add_subscriber ( keyring_identity * id , keypair * kp )
{
assert ( kp - > type = = KEYTYPE_CRYPTOBOX ) ;
id - > subscriber = find_subscriber ( kp - > public_key , SID_SIZE , 1 ) ;
2013-09-04 14:17:17 +00:00
if ( id - > subscriber ) {
2013-10-14 03:58:48 +00:00
if ( id - > subscriber - > reachable = = REACHABLE_NONE ) {
2013-09-04 14:17:17 +00:00
id - > subscriber - > reachable = REACHABLE_SELF ;
2013-10-14 03:58:48 +00:00
if ( ! my_subscriber )
my_subscriber = id - > subscriber ;
}
2013-09-04 14:17:17 +00:00
id - > subscriber - > identity = id ;
}
}
2014-10-31 04:30:52 +00:00
static void wipestr ( char * str )
{
while ( * str )
* str + + = ' ' ;
}
2012-04-10 03:25:46 +00:00
void keyring_free ( keyring_file * k )
{
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 ;
2013-09-03 08:01:10 +00:00
while ( b ) {
keyring_bam * last_bam = b ;
2012-04-10 03:25:46 +00:00
b = b - > next ;
/* Clear out any private data */
bzero ( last_bam , sizeof ( keyring_bam ) ) ;
/* release structure */
free ( last_bam ) ;
}
2014-10-31 04:30:52 +00:00
/* Free dynamically allocated salt strings.
2012-04-10 03:25:46 +00:00
Don ' t forget to overwrite any private data . */
2014-10-31 04:30:52 +00:00
if ( k - > KeyRingPin ) {
/* Wipe pin from local memory before freeing. */
wipestr ( k - > KeyRingPin ) ;
free ( k - > KeyRingPin ) ;
k - > KeyRingPin = NULL ;
}
if ( k - > KeyRingSalt ) {
bzero ( k - > KeyRingSalt , k - > KeyRingSaltLen ) ;
free ( k - > KeyRingSalt ) ;
k - > KeyRingSalt = NULL ;
k - > KeyRingSaltLen = 0 ;
}
/* Wipe out any loaded identities */
while ( k - > identities ) {
keyring_identity * i = k - > identities ;
k - > identities = i - > next ;
keyring_free_identity ( i ) ;
2014-10-31 03:13:23 +00:00
}
2012-04-10 03:25:46 +00:00
/* Wipe everything, just to be sure. */
bzero ( k , sizeof ( keyring_file ) ) ;
2013-11-01 01:42:37 +00:00
free ( k ) ;
2012-04-10 03:25:46 +00:00
return ;
}
2014-10-31 03:13:23 +00:00
int keyring_release_identity ( keyring_iterator * it )
2013-12-10 06:04:35 +00:00
{
2014-10-31 03:13:23 +00:00
assert ( it - > identity ) ;
2014-10-31 04:30:52 +00:00
keyring_identity * * i = & it - > file - > identities ;
2014-10-31 03:13:23 +00:00
while ( * i ) {
if ( ( * i ) = = it - > identity ) {
( * i ) = it - > identity - > next ;
keyring_free_identity ( it - > identity ) ;
it - > identity = ( * i ) ;
if ( it - > identity )
it - > keypair = it - > identity - > keypairs ;
else
2014-10-31 04:30:52 +00:00
it - > keypair = NULL ;
2014-10-31 03:13:23 +00:00
return 0 ;
}
i = & ( * i ) - > next ;
2013-10-10 03:52:20 +00:00
}
2014-10-31 03:13:23 +00:00
return WHY ( " Previous identity not found " ) ;
2013-10-10 03:52:20 +00:00
}
2014-10-31 03:13:23 +00:00
int keyring_release_subscriber ( keyring_file * k , const sid_t * sid )
2013-10-14 03:58:48 +00:00
{
2014-10-31 03:13:23 +00:00
keyring_iterator it ;
keyring_iterator_start ( k , & it ) ;
if ( ! keyring_find_sid ( & it , sid ) )
return WHYF ( " Keyring entry for %s not found " , alloca_tohex_sid_t ( * sid ) ) ;
if ( it . identity - > subscriber = = my_subscriber )
return WHYF ( " Cannot release my main subscriber " ) ;
return keyring_release_identity ( & it ) ;
2013-10-14 03:58:48 +00:00
}
2012-04-10 03:25:46 +00:00
void keyring_free_identity ( keyring_identity * id )
{
if ( id - > PKRPin ) {
2013-09-02 08:03:52 +00:00
/* Wipe pin from local memory before freeing. */
wipestr ( id - > PKRPin ) ;
free ( id - > PKRPin ) ;
id - > PKRPin = NULL ;
2012-04-10 03:25:46 +00:00
}
2014-10-31 03:13:23 +00:00
while ( id - > keypairs ) {
keypair * kp = id - > keypairs ;
id - > keypairs = kp - > next ;
keyring_free_keypair ( kp ) ;
}
2013-10-14 03:58:48 +00:00
if ( id - > subscriber )
link_stop_routing ( id - > subscriber ) ;
2012-04-10 03:25:46 +00:00
bzero ( id , sizeof ( keyring_identity ) ) ;
2013-10-10 03:52:20 +00:00
free ( id ) ;
2012-04-10 03:25:46 +00:00
return ;
}
2012-04-10 21:20:57 +00:00
/*
En / Decrypting a block requires use of the first 32 bytes of the block to provide
salt . The next 64 bytes constitute a message authentication code ( MAC ) that is
used to verify the validity of the block . The verification occurs in a higher
level function , and all we need to know here is that we shouldn ' t decrypt the
first 96 bytes of the block .
2012-04-12 04:30:51 +00:00
*/
2013-09-09 05:11:10 +00:00
static int keyring_munge_block (
unsigned char * block , int len /* includes the first 96 bytes */ ,
unsigned char * KeyRingSalt , int KeyRingSaltLen ,
const char * KeyRingPin , const char * PKRPin )
2012-04-10 21:20:57 +00:00
{
2015-07-06 08:19:49 +00:00
DEBUGF ( keyring , " KeyRingPin=%s PKRPin=%s " , alloca_str_toprint ( KeyRingPin ) , alloca_str_toprint ( PKRPin ) ) ;
2012-04-10 21:20:57 +00:00
int exit_code = 1 ;
unsigned char hashKey [ crypto_hash_sha512_BYTES ] ;
unsigned char hashNonce [ crypto_hash_sha512_BYTES ] ;
unsigned char work [ 65536 ] ;
if ( len < 96 ) return WHY ( " block too short " ) ;
unsigned char * PKRSalt = & block [ 0 ] ;
int PKRSaltLen = 32 ;
2012-04-11 06:17:22 +00:00
# if crypto_stream_xsalsa20_KEYBYTES>crypto_hash_sha512_BYTES
# error crypto primitive key size too long -- hash needs to be expanded
# endif
# if crypto_stream_xsalsa20_NONCEBYTES>crypto_hash_sha512_BYTES
# error crypto primitive nonce size too long -- hash needs to be expanded
# endif
2012-04-10 21:20:57 +00:00
/* Generate key and nonce hashes from the various inputs */
2013-03-07 03:57:33 +00:00
unsigned ofs ;
2013-03-06 04:58:57 +00:00
# define APPEND(buf, len) { \
2013-03-07 03:57:33 +00:00
assert ( ofs < = sizeof work ) ; \
2013-03-06 04:58:57 +00:00
unsigned __len = ( len ) ; \
2013-03-07 03:57:33 +00:00
if ( __len > sizeof work - ofs ) { \
2013-03-06 04:58:57 +00:00
WHY ( " Input too long " ) ; \
goto kmb_safeexit ; \
} \
bcopy ( ( buf ) , & work [ ofs ] , __len ) ; \
ofs + = __len ; \
}
2012-04-10 21:20:57 +00:00
/* Form key as hash of various concatenated inputs.
The ordering and repetition of the inputs is designed to make rainbow tables
infeasible */
ofs = 0 ;
APPEND ( PKRSalt , PKRSaltLen ) ;
APPEND ( PKRPin , strlen ( PKRPin ) ) ;
APPEND ( PKRSalt , PKRSaltLen ) ;
APPEND ( KeyRingPin , strlen ( KeyRingPin ) ) ;
crypto_hash_sha512 ( hashKey , work , ofs ) ;
/* Form the nonce as hash of various other concatenated inputs */
ofs = 0 ;
APPEND ( KeyRingPin , strlen ( KeyRingPin ) ) ;
APPEND ( KeyRingSalt , KeyRingSaltLen ) ;
APPEND ( KeyRingPin , strlen ( KeyRingPin ) ) ;
APPEND ( PKRPin , strlen ( PKRPin ) ) ;
crypto_hash_sha512 ( hashNonce , work , ofs ) ;
2013-09-03 08:01:10 +00:00
/* Now en/de-crypt the remainder of the block.
2012-04-11 06:17:22 +00:00
We do this in - place for convenience , so you should not pass in a mmap ( ) ' d
lump . */
2013-03-06 04:58:57 +00:00
crypto_stream_xsalsa20_xor ( & block [ 96 ] , & block [ 96 ] , len - 96 , hashNonce , hashKey ) ;
2012-04-11 06:17:22 +00:00
exit_code = 0 ;
2012-04-10 21:20:57 +00:00
kmb_safeexit :
/* Wipe out all sensitive structures before returning */
2012-04-11 06:17:22 +00:00
ofs = 0 ;
2012-04-10 21:20:57 +00:00
bzero ( & work [ 0 ] , 65536 ) ;
bzero ( & hashKey [ 0 ] , crypto_hash_sha512_BYTES ) ;
bzero ( & hashNonce [ 0 ] , crypto_hash_sha512_BYTES ) ;
return exit_code ;
2012-04-11 21:24:51 +00:00
# undef APPEND
2012-04-10 21:20:57 +00:00
}
2012-04-11 06:17:22 +00:00
2013-09-03 08:01:10 +00:00
static const char * keytype_str ( unsigned ktype , const char * unknown )
2013-04-30 07:59:06 +00:00
{
switch ( ktype ) {
case KEYTYPE_CRYPTOBOX : return " CRYPTOBOX " ;
case KEYTYPE_CRYPTOSIGN : return " CRYPTOSIGN " ;
case KEYTYPE_RHIZOME : return " RHIZOME " ;
case KEYTYPE_DID : return " DID " ;
2013-10-16 05:42:47 +00:00
case KEYTYPE_PUBLIC_TAG : return " PUBLIC_TAG " ;
2013-09-03 08:01:10 +00:00
default : return unknown ;
2013-04-30 07:59:06 +00:00
}
}
2013-04-29 05:01:50 +00:00
struct keytype {
size_t public_key_size ;
size_t private_key_size ;
size_t packed_size ;
2013-09-04 14:17:17 +00:00
void ( * creator ) ( keypair * ) ;
2013-09-02 08:03:52 +00:00
int ( * packer ) ( const keypair * , struct rotbuf * ) ;
2013-12-10 06:04:35 +00:00
int ( * unpacker ) ( keypair * , struct rotbuf * , size_t ) ;
2013-04-30 07:59:06 +00:00
void ( * dumper ) ( const keypair * , XPRINTF , int ) ;
2013-09-03 08:01:10 +00:00
int ( * loader ) ( keypair * , const char * ) ;
2013-04-29 05:01:50 +00:00
} ;
2013-09-04 14:17:17 +00:00
static void create_cryptobox ( keypair * kp )
{
/* Filter out public keys that start with 0x0, as they are reserved for address
abbreviation . */
do {
crypto_box_curve25519xsalsa20poly1305_keypair ( kp - > public_key , kp - > private_key ) ;
} while ( kp - > public_key [ 0 ] < 0x10 ) ;
}
2013-09-05 07:04:01 +00:00
/* Compute public key from private key.
*
* Public key calculation as below is taken from section 3 of :
* http : //cr.yp.to/highspeed/naclcrypto-20090310.pdf
*
* This can take a while on a mobile phone since it involves a scalarmult operation , so searching
* through all slots for a pin could take a while ( perhaps 1 second per pin : slot cominbation ) . This
* is both good and bad . The other option is to store the public key as well , which would make
* entering a pin faster , but would also make trying an incorrect pin faster , thus simplifying some
* brute - force attacks . We need to make a decision between speed / convenience and security here .
*/
static void _derive_scalarmult_public ( unsigned char * public , const unsigned char * private )
{
crypto_scalarmult_curve25519_base ( public , private ) ;
}
2013-09-04 14:17:17 +00:00
static void create_cryptosign ( keypair * kp )
{
crypto_sign_edwards25519sha512batch_keypair ( kp - > public_key , kp - > private_key ) ;
}
static void create_rhizome ( keypair * kp )
{
urandombytes ( kp - > private_key , kp - > private_key_len ) ;
}
2013-09-02 08:03:52 +00:00
static int pack_private_only ( const keypair * kp , struct rotbuf * rb )
2012-04-12 03:02:01 +00:00
{
2013-09-02 08:03:52 +00:00
rotbuf_putbuf ( rb , kp - > private_key , kp - > private_key_len ) ;
2013-04-29 05:01:50 +00:00
return 0 ;
}
2012-04-12 03:02:01 +00:00
2013-10-16 05:42:47 +00:00
static int pack_public_only ( const keypair * kp , struct rotbuf * rb )
{
rotbuf_putbuf ( rb , kp - > public_key , kp - > public_key_len ) ;
return 0 ;
}
2013-09-02 08:03:52 +00:00
static int pack_private_public ( const keypair * kp , struct rotbuf * rb )
2013-04-29 05:01:50 +00:00
{
2013-09-02 08:03:52 +00:00
rotbuf_putbuf ( rb , kp - > private_key , kp - > private_key_len ) ;
rotbuf_putbuf ( rb , kp - > public_key , kp - > public_key_len ) ;
2013-04-29 05:01:50 +00:00
return 0 ;
}
2012-04-12 03:02:01 +00:00
2013-09-05 07:04:01 +00:00
static void dump_private_public ( const keypair * kp , XPRINTF xpf , int include_secret )
2013-04-30 07:59:06 +00:00
{
if ( kp - > public_key_len )
xprintf ( xpf , " pub=%s " , alloca_tohex ( kp - > public_key , kp - > public_key_len ) ) ;
if ( include_secret & & kp - > private_key_len )
xprintf ( xpf , " sec=%s " , alloca_tohex ( kp - > private_key , kp - > private_key_len ) ) ;
}
2013-09-05 07:04:01 +00:00
static int _load_decode_hex ( const char * * hex , unsigned char * * buf , size_t * len )
{
const char * end = NULL ;
size_t hexlen = strn_fromhex ( NULL , - 1 , * hex , & end ) ;
if ( hexlen = = 0 | | end = = NULL | | ( * end ! = ' ' & & * end ! = ' \0 ' ) )
return WHY ( " malformed hex value " ) ;
if ( * len = = 0 ) {
assert ( * buf = = NULL ) ;
* len = hexlen ;
if ( ( * buf = emalloc_zero ( * len ) ) = = NULL )
return - 1 ;
}
else if ( hexlen ! = * len )
2013-09-09 02:39:40 +00:00
return WHYF ( " invalid hex value, incorrect length (expecting %zu bytes, got %zu) " , *len, hexlen) ;
2013-09-05 07:04:01 +00:00
strn_fromhex ( * buf , * len , * hex , hex ) ;
assert ( * hex = = end ) ;
return 0 ;
}
static int load_private_public ( keypair * kp , const char * text )
2013-09-02 08:03:52 +00:00
{
2013-09-05 07:04:01 +00:00
assert ( kp - > public_key_len ! = 0 ) ;
assert ( kp - > public_key ! = NULL ) ;
assert ( kp - > private_key_len ! = 0 ) ;
assert ( kp - > private_key ! = NULL ) ;
2013-09-03 08:01:10 +00:00
const char * t = text ;
2013-09-05 07:04:01 +00:00
int got_pub = 0 ;
int got_sec = 0 ;
2013-09-03 08:01:10 +00:00
while ( * t ) {
while ( isspace ( * t ) )
+ + t ;
if ( str_startswith ( t , " pub= " , & t ) ) {
2013-09-05 07:04:01 +00:00
if ( _load_decode_hex ( & t , & kp - > public_key , & kp - > public_key_len ) = = - 1 )
WHY ( " cannot decode pub= field " ) ;
else
got_pub = 1 ;
2013-09-03 08:01:10 +00:00
}
else if ( str_startswith ( t , " sec= " , & t ) ) {
2013-09-05 07:04:01 +00:00
if ( _load_decode_hex ( & t , & kp - > private_key , & kp - > private_key_len ) = = - 1 )
WHY ( " cannot decode sec= field " ) ;
else
got_sec = 1 ;
2013-09-03 08:01:10 +00:00
}
else if ( * t )
2013-09-05 07:04:01 +00:00
return WHYF ( " unsupported dump field: %s " , t ) ;
}
if ( ! got_sec )
return WHY ( " missing sec= field " ) ;
if ( ! got_pub )
return WHY ( " missing pub= field " ) ;
return 0 ;
}
static int load_private ( keypair * kp , const char * text )
{
assert ( kp - > private_key_len ! = 0 ) ;
assert ( kp - > private_key ! = NULL ) ;
const char * t = text ;
int got_sec = 0 ;
while ( * t ) {
while ( isspace ( * t ) )
+ + t ;
if ( str_startswith ( t , " sec= " , & t ) ) {
if ( _load_decode_hex ( & t , & kp - > private_key , & kp - > private_key_len ) = = - 1 )
WHY ( " cannot decode sec= field " ) ;
else
got_sec = 1 ;
} else if ( str_startswith ( t , " pub= " , & t ) ) {
WARN ( " skipping pub= field " ) ;
while ( * t & & ! isspace ( * t ) )
+ + t ;
}
else if ( * t )
return WHYF ( " unsupported dump field: %s " , t ) ;
}
if ( ! got_sec )
return WHY ( " missing sec= field " ) ;
return 0 ;
}
static int load_cryptobox ( keypair * kp , const char * text )
{
if ( load_private ( kp , text ) = = - 1 )
return - 1 ;
_derive_scalarmult_public ( kp - > public_key , kp - > private_key ) ;
return 0 ;
}
static int load_private_only ( keypair * kp , const char * text )
{
assert ( kp - > public_key_len = = 0 ) ;
assert ( kp - > public_key = = NULL ) ;
return load_private ( kp , text ) ;
}
static int load_unknown ( keypair * kp , const char * text )
{
assert ( kp - > private_key_len = = 0 ) ;
assert ( kp - > private_key = = NULL ) ;
assert ( kp - > public_key_len = = 0 ) ;
assert ( kp - > public_key = = NULL ) ;
const char * t = text ;
while ( * t ) {
while ( isspace ( * t ) )
+ + t ;
if ( str_startswith ( t , " pub= " , & t ) ) {
if ( _load_decode_hex ( & t , & kp - > public_key , & kp - > public_key_len ) = = - 1 )
WHY ( " cannot decode pub= field " ) ;
}
else if ( str_startswith ( t , " sec= " , & t ) ) {
if ( _load_decode_hex ( & t , & kp - > private_key , & kp - > private_key_len ) = = - 1 )
WHY ( " cannot decode sec= field " ) ;
}
else if ( * t )
return WHYF ( " unsupported dump field: %s " , t ) ;
2013-09-03 08:01:10 +00:00
}
2013-09-02 08:03:52 +00:00
return 0 ;
}
2013-12-10 06:04:35 +00:00
static int unpack_private_public ( keypair * kp , struct rotbuf * rb , size_t key_length )
2013-04-29 05:01:50 +00:00
{
2013-12-09 07:52:18 +00:00
assert ( key_length = = kp - > private_key_len + kp - > public_key_len ) ;
2013-09-03 08:01:10 +00:00
rotbuf_getbuf ( rb , kp - > private_key , kp - > private_key_len ) ;
rotbuf_getbuf ( rb , kp - > public_key , kp - > public_key_len ) ;
2013-04-29 05:01:50 +00:00
return 0 ;
}
2013-12-10 06:04:35 +00:00
static int unpack_private_only ( keypair * kp , struct rotbuf * rb , size_t key_length )
2013-04-29 05:01:50 +00:00
{
2013-10-16 03:11:20 +00:00
if ( ! kp - > private_key ) {
kp - > private_key_len = key_length ;
if ( ( kp - > private_key = emalloc ( kp - > private_key_len ) ) = = NULL )
return - 1 ;
}
2013-09-03 08:01:10 +00:00
rotbuf_getbuf ( rb , kp - > private_key , kp - > private_key_len ) ;
2013-04-29 05:01:50 +00:00
return 0 ;
}
2013-12-10 06:04:35 +00:00
static int unpack_public_only ( keypair * kp , struct rotbuf * rb , size_t key_length )
2013-10-16 05:42:47 +00:00
{
if ( ! kp - > public_key ) {
kp - > public_key_len = key_length ;
if ( ( kp - > public_key = emalloc ( kp - > public_key_len ) ) = = NULL )
return - 1 ;
}
rotbuf_getbuf ( rb , kp - > public_key , kp - > public_key_len ) ;
return 0 ;
}
2013-12-10 06:04:35 +00:00
static int unpack_cryptobox ( keypair * kp , struct rotbuf * rb , size_t key_length )
2013-04-29 05:01:50 +00:00
{
2013-12-09 07:52:18 +00:00
assert ( key_length = = kp - > private_key_len ) ;
2013-09-03 08:01:10 +00:00
rotbuf_getbuf ( rb , kp - > private_key , kp - > private_key_len ) ;
2013-04-29 05:01:50 +00:00
if ( ! rb - > wrap )
2013-09-05 07:04:01 +00:00
_derive_scalarmult_public ( kp - > public_key , kp - > private_key ) ;
2013-04-29 05:01:50 +00:00
return 0 ;
}
2012-04-12 03:02:01 +00:00
2013-09-02 08:03:52 +00:00
static int pack_did_name ( const keypair * kp , struct rotbuf * rb )
2013-04-29 05:01:50 +00:00
{
// Ensure name is nul terminated.
2013-09-02 08:03:52 +00:00
if ( strnchr ( ( const char * ) kp - > public_key , kp - > public_key_len , ' \0 ' ) = = NULL )
2013-04-29 05:01:50 +00:00
return WHY ( " missing nul terminator " ) ;
2013-09-02 08:03:52 +00:00
return pack_private_public ( kp , rb ) ;
2013-04-29 05:01:50 +00:00
}
2013-12-10 06:04:35 +00:00
static int unpack_did_name ( keypair * kp , struct rotbuf * rb , size_t key_length )
2013-04-29 05:01:50 +00:00
{
2013-10-16 03:11:20 +00:00
if ( unpack_private_public ( kp , rb , key_length ) = = - 1 )
2013-04-29 05:01:50 +00:00
return - 1 ;
// Fail if name is not nul terminated.
2013-09-03 08:01:10 +00:00
return strnchr ( ( const char * ) kp - > public_key , kp - > public_key_len , ' \0 ' ) = = NULL ? - 1 : 0 ;
2013-04-29 05:01:50 +00:00
}
2012-04-12 03:02:01 +00:00
2013-12-09 07:52:18 +00:00
static void dump_did_name ( const keypair * kp , XPRINTF xpf , int UNUSED ( include_secret ) )
2013-04-30 07:59:06 +00:00
{
xprintf ( xpf , " DID=%s " , alloca_str_toprint_quoted ( ( const char * ) kp - > private_key , " \" \" " ) ) ;
xprintf ( xpf , " Name=%s " , alloca_str_toprint_quoted ( ( const char * ) kp - > public_key , " \" \" " ) ) ;
}
2013-09-03 08:01:10 +00:00
static int load_did_name ( keypair * kp , const char * text )
2013-09-02 08:03:52 +00:00
{
2013-09-03 08:01:10 +00:00
assert ( kp - > public_key ! = NULL ) ;
assert ( kp - > private_key ! = NULL ) ;
const char * t = text ;
int got_did = 0 ;
int got_name = 0 ;
while ( * t ) {
while ( isspace ( * t ) )
+ + t ;
if ( str_startswith ( t , " DID= \" " , & t ) ) {
if ( got_did )
return WHY ( " duplicate DID " ) ;
const char * e = NULL ;
bzero ( kp - > private_key , kp - > private_key_len ) ;
2013-10-17 12:45:25 +00:00
strn_fromprint ( kp - > private_key , kp - > private_key_len , t , 0 , ' " ' , & e ) ;
2013-09-03 08:01:10 +00:00
if ( * e ! = ' " ' )
return WHY ( " malformed DID quoted string " ) ;
t = e + 1 ;
got_did = 1 ;
} else if ( str_startswith ( t , " Name= \" " , & t ) ) {
if ( got_name )
return WHY ( " duplicate Name " ) ;
const char * e = NULL ;
bzero ( kp - > public_key , kp - > public_key_len ) ;
2013-10-17 12:45:25 +00:00
strn_fromprint ( kp - > public_key , kp - > public_key_len , t , 0 , ' " ' , & e ) ;
2013-09-03 08:01:10 +00:00
if ( * e ! = ' " ' )
return WHY ( " malformed Name quoted string " ) ;
t = e + 1 ;
got_name = 1 ;
}
else if ( * t )
return WHYF ( " unsupported dump content: %s " , t ) ;
}
if ( ! got_did )
2013-09-02 08:03:52 +00:00
return WHY ( " missing DID " ) ;
2013-09-03 08:01:10 +00:00
if ( ! got_name )
2013-09-02 08:03:52 +00:00
return WHY ( " missing Name " ) ;
return 0 ;
}
2013-04-29 05:01:50 +00:00
/* This is where all the supported key types are declared. In order to preserve backward
* compatibility ( reading keyring files from older versions of Serval DNA ) , DO NOT ERASE OR RE - USE
* ANY KEY TYPE ENTRIES FROM THIS ARRAY . If a key type is no longer used , it must be permanently
* deprecated , ie , recognised and simply skipped . The packer and unpacker functions can be changed
* to NULL .
*/
const struct keytype keytypes [ ] = {
[ KEYTYPE_CRYPTOBOX ] = {
/* Only the private key is stored, and the public key (SID) is derived from the private key
* when the keyring is read .
*/
. private_key_size = crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES ,
. public_key_size = crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES ,
. packed_size = crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES ,
2013-09-04 14:17:17 +00:00
. creator = create_cryptobox ,
2013-04-29 05:01:50 +00:00
. packer = pack_private_only ,
2013-09-05 07:04:01 +00:00
. unpacker = unpack_cryptobox ,
. dumper = dump_private_public ,
. loader = load_cryptobox
2013-04-29 05:01:50 +00:00
} ,
[ KEYTYPE_CRYPTOSIGN ] = {
/* The NaCl API does not expose any method to derive a cryptosign public key from its private
* key , although there must be an internal NaCl function to do so . Subverting the NaCl API to
* invoke that function risks incompatibility with future releases of NaCl , so instead the
* public key is stored redundantly in the keyring .
*/
. private_key_size = crypto_sign_edwards25519sha512batch_SECRETKEYBYTES ,
. public_key_size = crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES ,
. packed_size = crypto_sign_edwards25519sha512batch_SECRETKEYBYTES + crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES ,
2013-09-04 14:17:17 +00:00
. creator = create_cryptosign ,
2013-04-29 05:01:50 +00:00
. packer = pack_private_public ,
2013-04-30 07:59:06 +00:00
. unpacker = unpack_private_public ,
2013-09-05 07:04:01 +00:00
. dumper = dump_private_public ,
. loader = load_private_public
2013-04-29 05:01:50 +00:00
} ,
[ KEYTYPE_RHIZOME ] = {
2013-06-06 06:33:35 +00:00
/* The Rhizome Secret (a large, unguessable number) is stored in the private key field, and
* the public key field is not used .
2013-04-29 05:01:50 +00:00
*/
. private_key_size = 32 ,
. public_key_size = 0 ,
. packed_size = 32 ,
2013-09-04 14:17:17 +00:00
. creator = create_rhizome ,
2013-04-29 05:01:50 +00:00
. packer = pack_private_only ,
2013-04-30 07:59:06 +00:00
. unpacker = unpack_private_only ,
2013-09-05 07:04:01 +00:00
. dumper = dump_private_public ,
. loader = load_private_only
2013-04-29 05:01:50 +00:00
} ,
[ KEYTYPE_DID ] = {
/* The DID is stored in unpacked form in the private key field, and the name in nul-terminated
* ASCII form in the public key field .
*/
. private_key_size = 32 ,
. public_key_size = 64 ,
. packed_size = 32 + 64 ,
2013-09-04 14:17:17 +00:00
. creator = NULL , // not included in a newly created identity
2013-04-29 05:01:50 +00:00
. packer = pack_did_name ,
2013-04-30 07:59:06 +00:00
. unpacker = unpack_did_name ,
2013-09-02 08:03:52 +00:00
. dumper = dump_did_name ,
. loader = load_did_name
2013-10-16 05:42:47 +00:00
} ,
[ KEYTYPE_PUBLIC_TAG ] = {
. private_key_size = 0 ,
. public_key_size = 0 , // size is derived from the stored key length
. packed_size = 0 ,
. creator = NULL , // not included in a newly created identity
. packer = pack_public_only ,
. unpacker = unpack_public_only ,
. dumper = dump_private_public ,
. loader = load_unknown
2013-04-29 05:01:50 +00:00
}
// ADD MORE KEY TYPES HERE
} ;
2012-04-12 03:02:01 +00:00
2013-09-02 08:03:52 +00:00
static void keyring_free_keypair ( keypair * kp )
{
if ( kp - > private_key ) {
bzero ( kp - > private_key , kp - > private_key_len ) ;
free ( kp - > private_key ) ;
}
if ( kp - > public_key ) {
bzero ( kp - > public_key , kp - > public_key_len ) ;
free ( kp - > public_key ) ;
}
bzero ( kp , sizeof ( keypair ) ) ;
2013-10-10 03:52:20 +00:00
free ( kp ) ;
2013-09-02 08:03:52 +00:00
}
static keypair * keyring_alloc_keypair ( unsigned ktype , size_t len )
{
assert ( ktype ! = 0 ) ;
keypair * kp = emalloc_zero ( sizeof ( keypair ) ) ;
if ( ! kp )
return NULL ;
kp - > type = ktype ;
if ( ktype < NELS ( keytypes ) ) {
kp - > private_key_len = keytypes [ ktype ] . private_key_size ;
kp - > public_key_len = keytypes [ ktype ] . public_key_size ;
} else {
kp - > private_key_len = len ;
kp - > public_key_len = 0 ;
}
2013-09-04 14:17:17 +00:00
if ( ( kp - > private_key_len & & ( kp - > private_key = emalloc ( kp - > private_key_len ) ) = = NULL )
| | ( kp - > public_key_len & & ( kp - > public_key = emalloc ( kp - > public_key_len ) ) = = NULL )
2013-09-02 08:03:52 +00:00
) {
keyring_free_keypair ( kp ) ;
return NULL ;
}
return kp ;
}
2013-09-05 07:04:01 +00:00
static int keyring_pack_identity ( const keyring_identity * id , unsigned char packed [ KEYRING_PAGE_SIZE ] )
2013-04-29 05:01:50 +00:00
{
/* Convert an identity to a KEYRING_PAGE_SIZE bytes long block that consists of 32 bytes of random
* salt , a 64 byte ( 512 bit ) message authentication code ( MAC ) and the list of key pairs . */
if ( urandombytes ( packed , PKR_SALT_BYTES ) = = - 1 )
return WHY ( " Could not generate salt " ) ;
/* Calculate MAC */
2013-09-05 07:04:01 +00:00
if ( keyring_identity_mac ( id , packed /* pkr salt */ , packed + PKR_SALT_BYTES /* write mac in after salt */ ) = = - 1 )
return - 1 ;
2013-04-29 05:01:50 +00:00
/* There was a known plain-text opportunity here: byte 96 must be 0x01, and some other bytes are
* likely deducible , e . g . , the location of the trailing 0x00 byte can probably be guessed with
* confidence . Payload rotation will frustrate this attack .
*/
uint16_t rotation ;
if ( urandombytes ( ( unsigned char * ) & rotation , sizeof rotation ) = = - 1 )
2012-04-12 04:30:51 +00:00
return WHY ( " urandombytes() failed to generate random rotation " ) ;
2012-04-12 06:22:41 +00:00
# ifdef NO_ROTATION
rotation = 0 ;
# endif
2013-04-29 05:01:50 +00:00
// The two bytes immediately following the MAC describe the rotation offset.
packed [ PKR_SALT_BYTES + PKR_MAC_BYTES ] = rotation > > 8 ;
packed [ PKR_SALT_BYTES + PKR_MAC_BYTES + 1 ] = rotation & 0xff ;
/* Pack the key pairs into the rest of the slot as a rotated buffer. */
struct rotbuf rbuf ;
rotbuf_init ( & rbuf ,
packed + PKR_SALT_BYTES + PKR_MAC_BYTES + 2 ,
KEYRING_PAGE_SIZE - ( PKR_SALT_BYTES + PKR_MAC_BYTES + 2 ) ,
rotation ) ;
2014-10-31 03:13:23 +00:00
keypair * kp = id - > keypairs ;
while ( kp & & ! rbuf . wrap ) {
unsigned ktype = kp - > type ;
2013-09-03 08:01:10 +00:00
const char * kts = keytype_str ( ktype , " unknown " ) ;
2013-09-02 08:03:52 +00:00
int ( * packer ) ( const keypair * , struct rotbuf * ) = NULL ;
2013-10-16 05:42:47 +00:00
size_t keypair_len = 0 ;
2013-04-29 05:01:50 +00:00
const struct keytype * kt = & keytypes [ ktype ] ;
2013-09-02 08:03:52 +00:00
if ( ktype = = 0x00 )
FATALF ( " ktype=0 in keypair kp=%u " , kp ) ;
if ( ktype < NELS ( keytypes ) ) {
packer = kt - > packer ;
keypair_len = kt - > packed_size ;
2013-10-16 05:42:47 +00:00
if ( keypair_len = = 0 ) {
2014-10-31 03:13:23 +00:00
keypair_len = kp - > private_key_len + kp - > public_key_len ;
2013-10-16 05:42:47 +00:00
}
2013-09-02 08:03:52 +00:00
} else {
packer = pack_private_only ;
2014-10-31 03:13:23 +00:00
keypair_len = kp - > private_key_len ;
2013-04-29 05:01:50 +00:00
}
2013-09-02 08:03:52 +00:00
if ( packer = = NULL ) {
2013-09-03 08:01:10 +00:00
WARNF ( " no packer function for key type 0x%02x(%s), omitted from keyring file " , ktype , kts ) ;
2013-09-02 08:03:52 +00:00
} else {
2015-07-06 08:19:49 +00:00
DEBUGF ( keyring , " pack key type = 0x%02x(%s) " , ktype , kts ) ;
2013-09-02 08:03:52 +00:00
// First byte is the key type code.
rotbuf_putc ( & rbuf , ktype ) ;
// The next two bytes are the key pair length, for forward compatibility: so older software can
// skip over key pairs with an unrecognised type. The original four first key types do not
// store the length, for the sake of backward compatibility with legacy keyring files. Their
// entry lengths are hard-coded.
switch ( ktype ) {
case KEYTYPE_CRYPTOBOX :
case KEYTYPE_CRYPTOSIGN :
case KEYTYPE_RHIZOME :
case KEYTYPE_DID :
break ;
default :
rotbuf_putc ( & rbuf , ( keypair_len > > 8 ) & 0xff ) ;
rotbuf_putc ( & rbuf , keypair_len & 0xff ) ;
break ;
}
// The remaining bytes is the key pair in whatever format it uses.
struct rotbuf rbstart = rbuf ;
2014-10-31 03:13:23 +00:00
if ( packer ( kp , & rbuf ) ! = 0 )
2013-09-02 08:03:52 +00:00
break ;
// Ensure the correct number of bytes were written.
unsigned packed = rotbuf_delta ( & rbstart , & rbuf ) ;
if ( packed ! = keypair_len ) {
2013-09-03 08:01:10 +00:00
WHYF ( " key type 0x%02x(%s) packed wrong length (packed %u, expecting %u) " , ktype , kts , packed , ( int ) keypair_len ) ;
2013-09-02 08:03:52 +00:00
goto scram ;
}
2013-04-29 05:01:50 +00:00
}
2014-10-31 03:13:23 +00:00
kp = kp - > next ;
2013-04-29 05:01:50 +00:00
}
// Final byte is a zero key type code.
rotbuf_putc ( & rbuf , 0x00 ) ;
if ( rbuf . wrap > 1 ) {
WHY ( " slot overrun " ) ;
goto scram ;
}
2014-10-31 03:13:23 +00:00
if ( kp ) {
2013-04-29 05:01:50 +00:00
WHY ( " error filling slot " ) ;
goto scram ;
}
/* Randomfill the remaining part of the slot to frustrate any known-plain-text attack on the
* keyring .
*/
{
unsigned char * buf ;
size_t len ;
while ( rotbuf_next_chunk ( & rbuf , & buf , & len ) )
if ( urandombytes ( buf , len ) )
return WHY ( " urandombytes() failed to back - fill packed identity block " ) ;
}
return 0 ;
scram :
/* Randomfill the entire slot to erase any secret keys that may have found their way into it, to
* avoid leaking sensitive information out through a possibly re - used memory buffer .
*/
if ( urandombytes ( packed , KEYRING_PAGE_SIZE ) = = - 1 )
WHY ( " urandombytes() failed to in-fill packed identity block " ) ;
return - 1 ;
2012-04-12 03:02:01 +00:00
}
2013-04-30 07:59:06 +00:00
static int cmp_keypair ( const keypair * a , const keypair * b )
{
2014-10-31 03:13:23 +00:00
int c ;
if ( a - > type < b - > type )
return - 1 ;
if ( a - > type > b - > type )
return 1 ;
if ( a - > public_key_len & & ! b - > public_key_len )
return - 1 ;
if ( ! a - > public_key_len & & b - > public_key_len )
return 1 ;
if ( a - > public_key_len & & b - > public_key_len ) {
2013-04-30 07:59:06 +00:00
assert ( a - > public_key ! = NULL ) ;
assert ( b - > public_key ! = NULL ) ;
2013-12-10 06:04:35 +00:00
size_t len = a - > public_key_len ;
if ( len > b - > public_key_len )
len = b - > public_key_len ;
2013-10-16 05:42:47 +00:00
c = memcmp ( a - > public_key , b - > public_key , len ) ;
if ( c = = 0 & & a - > public_key_len ! = b - > public_key_len )
c = a - > public_key_len - b - > public_key_len ;
2014-10-31 03:13:23 +00:00
if ( c )
return c ;
2013-04-30 07:59:06 +00:00
}
2014-10-31 03:13:23 +00:00
if ( a - > private_key_len & & ! b - > private_key_len )
return - 1 ;
if ( ! a - > private_key_len & & b - > private_key_len )
return 1 ;
if ( a - > private_key_len & & b - > private_key_len ) {
2013-04-30 07:59:06 +00:00
assert ( a - > private_key ! = NULL ) ;
assert ( b - > private_key ! = NULL ) ;
2013-12-10 06:04:35 +00:00
size_t len = a - > private_key_len ;
if ( len > b - > private_key_len )
len = b - > private_key_len ;
2013-10-16 05:42:47 +00:00
c = memcmp ( a - > private_key , b - > private_key , len ) ;
if ( c = = 0 & & a - > private_key_len ! = b - > private_key_len )
c = a - > private_key_len - b - > private_key_len ;
2014-10-31 03:13:23 +00:00
if ( c )
return c ;
2013-04-30 07:59:06 +00:00
}
2014-10-31 03:13:23 +00:00
return 0 ;
2013-04-30 07:59:06 +00:00
}
2013-09-06 18:33:28 +00:00
/* Ensure that regardless of the order in the keyring file or loaded dump, keypairs are always
* stored in memory in ascending order of ( key type , public key , private key ) .
*/
2013-09-03 08:01:10 +00:00
static int keyring_identity_add_keypair ( keyring_identity * id , keypair * kp )
{
2014-10-31 03:13:23 +00:00
assert ( id ) ;
assert ( kp ) ;
keypair * * ptr = & id - > keypairs ;
2013-09-03 08:01:10 +00:00
int c = 1 ;
2014-10-31 03:13:23 +00:00
while ( * ptr & & ( c = cmp_keypair ( * ptr , kp ) ) < 0 )
ptr = & ( * ptr ) - > next ;
2013-09-03 08:01:10 +00:00
if ( c = = 0 )
return 0 ; // duplicate not inserted
2014-10-31 03:13:23 +00:00
kp - > next = * ptr ;
* ptr = kp ;
2013-09-03 08:01:10 +00:00
return 1 ;
}
2013-04-29 05:01:50 +00:00
static keyring_identity * keyring_unpack_identity ( unsigned char * slot , const char * pin )
2012-04-11 06:17:22 +00:00
{
/* Skip salt and MAC */
2013-03-06 04:13:52 +00:00
keyring_identity * id = emalloc_zero ( sizeof ( keyring_identity ) ) ;
2013-09-02 08:03:52 +00:00
if ( ! id )
return NULL ;
2013-03-06 04:13:52 +00:00
id - > PKRPin = str_edup ( pin ) ;
2013-04-29 05:01:50 +00:00
// The two bytes immediately following the MAC describe the rotation offset.
uint16_t rotation = ( slot [ PKR_SALT_BYTES + PKR_MAC_BYTES ] < < 8 ) | slot [ PKR_SALT_BYTES + PKR_MAC_BYTES + 1 ] ;
/* Pack the key pairs into the rest of the slot as a rotated buffer. */
struct rotbuf rbuf ;
rotbuf_init ( & rbuf ,
slot + PKR_SALT_BYTES + PKR_MAC_BYTES + 2 ,
KEYRING_PAGE_SIZE - ( PKR_SALT_BYTES + PKR_MAC_BYTES + 2 ) ,
rotation ) ;
while ( ! rbuf . wrap ) {
2013-04-30 07:59:06 +00:00
struct rotbuf rbo = rbuf ;
2013-04-29 05:01:50 +00:00
unsigned char ktype = rotbuf_getc ( & rbuf ) ;
if ( rbuf . wrap | | ktype = = 0x00 )
break ; // End of data, stop looking
const struct keytype * kt = & keytypes [ ktype ] ;
size_t keypair_len ;
// No length bytes after the original four key types, for backward compatibility. All other key
// types are followed by a two-byte keypair length.
2013-04-23 08:43:01 +00:00
switch ( ktype ) {
case KEYTYPE_CRYPTOBOX :
case KEYTYPE_CRYPTOSIGN :
case KEYTYPE_RHIZOME :
case KEYTYPE_DID :
2013-04-29 05:01:50 +00:00
keypair_len = kt - > packed_size ;
2013-04-23 08:43:01 +00:00
break ;
default :
2013-04-29 05:01:50 +00:00
keypair_len = rotbuf_getc ( & rbuf ) < < 8 ;
keypair_len | = rotbuf_getc ( & rbuf ) ;
break ;
2013-04-23 08:43:01 +00:00
}
2013-09-03 08:01:10 +00:00
if ( keypair_len > rotbuf_remain ( & rbuf ) ) {
2015-07-06 08:19:49 +00:00
DEBUGF ( keyring , " invalid keypair length %zu " , keypair_len ) ;
2013-09-03 08:01:10 +00:00
keyring_free_identity ( id ) ;
return NULL ;
}
2013-09-02 08:03:52 +00:00
// Create keyring entry to hold the key pair. Even entries of unknown type are stored,
// so they can be dumped.
keypair * kp = keyring_alloc_keypair ( ktype , keypair_len ) ;
2013-09-03 08:01:10 +00:00
if ( kp = = NULL ) {
keyring_free_identity ( id ) ;
2013-09-02 08:03:52 +00:00
return NULL ;
2013-09-03 08:01:10 +00:00
}
2013-09-02 08:03:52 +00:00
struct rotbuf rbstart = rbuf ;
2013-04-29 05:01:50 +00:00
if ( ktype < NELS ( keytypes ) & & kt - > unpacker ) {
2015-07-06 08:19:49 +00:00
DEBUGF ( keyring , " unpack key type = 0x%02x(%s) at offset %u " , ktype , keytype_str ( ktype , " unknown " ) , ( int ) rotbuf_position ( & rbo ) ) ;
2013-10-16 03:11:20 +00:00
if ( kt - > unpacker ( kp , & rbuf , keypair_len ) ! = 0 ) {
2013-09-03 08:01:10 +00:00
// If there is an error, it is probably an empty slot.
2015-07-06 08:19:49 +00:00
DEBUGF ( keyring , " key type 0x%02x does not unpack " , ktype ) ;
2013-09-03 08:01:10 +00:00
keyring_free_keypair ( kp ) ;
2013-04-29 05:01:50 +00:00
keyring_free_identity ( id ) ;
return NULL ;
2012-04-11 06:17:22 +00:00
}
2013-09-03 08:01:10 +00:00
// Ensure that the correct number of bytes was consumed.
size_t unpacked = rotbuf_delta ( & rbstart , & rbuf ) ;
if ( unpacked ! = keypair_len ) {
// If the number of bytes unpacked does not match the keypair length, it is probably an
// empty slot.
2015-07-06 08:19:49 +00:00
DEBUGF ( keyring , " key type 0x%02x unpacked wrong length (unpacked %u, expecting %u) " , ktype , ( int ) unpacked , ( int ) keypair_len ) ;
2013-09-03 08:01:10 +00:00
keyring_free_keypair ( kp ) ;
2013-04-29 05:01:50 +00:00
keyring_free_identity ( id ) ;
return NULL ;
}
} else {
2015-07-06 08:19:49 +00:00
DEBUGF ( keyring , " unsupported key type 0x%02x at offset %u, reading %u bytes as private key " , ktype , ( unsigned ) rotbuf_position ( & rbo ) , ( unsigned ) kp - > private_key_len ) ;
2013-09-03 08:01:10 +00:00
assert ( kp - > public_key_len = = 0 ) ;
assert ( kp - > public_key = = NULL ) ;
2013-09-02 08:03:52 +00:00
rotbuf_getbuf ( & rbuf , kp - > private_key , kp - > private_key_len ) ;
}
// Got a valid key pair! Sort the key pairs by (key type, public key, private key) and weed
// out duplicates.
2013-09-03 08:01:10 +00:00
if ( ! keyring_identity_add_keypair ( id , kp ) )
keyring_free_keypair ( kp ) ;
2013-04-23 08:43:01 +00:00
}
// If the buffer offset overshot, we got an invalid keypair code and length combination.
2013-04-29 05:01:50 +00:00
if ( rbuf . wrap > 1 ) {
2015-07-06 08:19:49 +00:00
DEBUGF ( keyring , " slot overrun by %u bytes " , rbuf . wrap - 1 ) ;
2013-04-23 08:43:01 +00:00
keyring_free_identity ( id ) ;
return NULL ;
}
2016-01-12 04:35:41 +00:00
if ( ! id - > keypairs | | id - > keypairs - > type ! = KEYTYPE_CRYPTOBOX ) {
DEBUGF ( keyring , " first keypair is not type CRYPTOBOX " ) ;
keyring_free_identity ( id ) ;
return NULL ;
}
2015-07-06 08:19:49 +00:00
DEBUGF ( keyring , " unpacked key pairs " ) ;
2012-04-11 06:17:22 +00:00
return id ;
}
2013-09-05 07:04:01 +00:00
static int keyring_identity_mac ( const keyring_identity * id , unsigned char * pkrsalt , unsigned char * mac )
2012-04-12 03:02:01 +00:00
{
unsigned char work [ 65536 ] ;
2013-03-07 03:57:33 +00:00
unsigned ofs = 0 ;
2013-03-06 03:32:33 +00:00
# define APPEND(buf, len) { \
2013-03-07 03:57:33 +00:00
assert ( ofs < = sizeof work ) ; \
2013-03-06 03:32:33 +00:00
unsigned __len = ( len ) ; \
2013-03-07 03:57:33 +00:00
if ( __len > sizeof work - ofs ) { \
2013-03-06 03:32:33 +00:00
bzero ( work , ofs ) ; \
return WHY ( " Input too long " ) ; \
} \
bcopy ( ( buf ) , & work [ ofs ] , __len ) ; \
ofs + = __len ; \
}
APPEND ( & pkrsalt [ 0 ] , 32 ) ;
2014-10-31 03:13:23 +00:00
keypair * kp = id - > keypairs ;
if ( ! kp | | kp - > type ! = KEYTYPE_CRYPTOBOX )
2013-09-05 07:04:01 +00:00
return WHY ( " first keypair is not type CRYPTOBOX " ) ;
2014-10-31 03:13:23 +00:00
APPEND ( kp - > private_key , kp - > private_key_len ) ;
APPEND ( kp - > public_key , kp - > public_key_len ) ;
2013-03-06 03:32:33 +00:00
APPEND ( id - > PKRPin , strlen ( id - > PKRPin ) ) ;
2013-04-29 05:01:50 +00:00
# undef APPEND
2013-03-06 03:32:33 +00:00
crypto_hash_sha512 ( mac , work , ofs ) ;
2012-04-12 03:02:01 +00:00
return 0 ;
}
2013-09-02 08:03:52 +00:00
/* Read the slot, and try to decrypt it. Decryption is symmetric with encryption, so the same
* function is used for munging the slot before making use of it , whichever way we are going . Once
* munged , we then need to verify that the slot is valid , and if so unpack the details of the
* identity .
*/
2014-10-31 04:30:52 +00:00
static int keyring_decrypt_pkr ( keyring_file * k , const char * pin , int slot_number )
2012-04-11 06:17:22 +00:00
{
2015-07-06 08:19:49 +00:00
DEBUGF ( keyring , " k=%p, pin=%s slot_number=%d " , k , alloca_str_toprint ( pin ) , slot_number ) ;
2012-04-11 06:17:22 +00:00
unsigned char slot [ KEYRING_PAGE_SIZE ] ;
2013-03-07 03:57:33 +00:00
keyring_identity * id = NULL ;
2012-04-11 06:17:22 +00:00
/* 1. Read slot. */
if ( fseeko ( k - > file , slot_number * KEYRING_PAGE_SIZE , SEEK_SET ) )
2012-07-27 08:48:57 +00:00
return WHY_perror ( " fseeko " ) ;
2013-09-05 07:04:01 +00:00
if ( fread ( slot , KEYRING_PAGE_SIZE , 1 , k - > file ) ! = 1 )
2012-07-27 08:48:57 +00:00
return WHY_perror ( " fread " ) ;
2012-04-11 06:17:22 +00:00
/* 2. Decrypt data from slot. */
2014-10-31 04:30:52 +00:00
if ( keyring_munge_block ( slot , KEYRING_PAGE_SIZE , k - > KeyRingSalt , k - > KeyRingSaltLen , k - > KeyRingPin , pin ) ) {
2013-04-30 07:59:06 +00:00
WHYF ( " keyring_munge_block() failed, slot=%u " , slot_number ) ;
2012-04-11 06:17:22 +00:00
goto kdp_safeexit ;
}
2013-03-07 03:57:33 +00:00
/* 3. Unpack contents of slot into a new identity in the provided context. */
2015-07-06 08:19:49 +00:00
DEBUGF ( keyring , " unpack slot %u " , slot_number ) ;
2014-10-31 03:13:23 +00:00
if ( ( ( id = keyring_unpack_identity ( slot , pin ) ) = = NULL ) | | ! id - > keypairs )
2013-03-07 03:57:33 +00:00
goto kdp_safeexit ; // Not a valid slot
id - > slot = slot_number ;
2012-04-11 06:17:22 +00:00
/* 4. Verify that slot is self-consistent (check MAC) */
2013-09-05 07:04:01 +00:00
unsigned char hash [ crypto_hash_sha512_BYTES ] ;
if ( keyring_identity_mac ( id , slot , hash ) )
2012-04-12 03:02:01 +00:00
goto kdp_safeexit ;
2012-04-11 21:24:51 +00:00
/* compare hash to record */
2013-09-05 07:04:01 +00:00
if ( memcmp ( hash , & slot [ PKR_SALT_BYTES ] , crypto_hash_sha512_BYTES ) ) {
2016-01-12 04:35:41 +00:00
DEBUGF ( keyring , " slot %u is not valid (MAC mismatch) " , slot_number ) ;
if ( IF_DEBUG ( keyring ) ) {
dump ( " computed " , hash , crypto_hash_sha512_BYTES ) ;
dump ( " stored " , & slot [ PKR_SALT_BYTES ] , crypto_hash_sha512_BYTES ) ;
}
2013-09-03 08:01:10 +00:00
goto kdp_safeexit ;
}
2014-10-31 03:13:23 +00:00
2013-09-05 07:04:01 +00:00
// Add any unlocked subscribers to our memory table, flagged as local SIDs.
2014-10-31 03:13:23 +00:00
keypair * kp = keyring_identity_keytype ( id , KEYTYPE_CRYPTOBOX ) ;
if ( kp )
add_subscriber ( id , kp ) ;
2013-09-05 07:04:01 +00:00
/* All fine, so add the id into the context and return. */
2014-10-31 04:30:52 +00:00
keyring_identity * * i = & k - > identities ;
2014-10-31 03:13:23 +00:00
while ( * i )
i = & ( * i ) - > next ;
* i = id ;
2012-04-11 21:24:51 +00:00
return 0 ;
2012-04-11 06:17:22 +00:00
kdp_safeexit :
/* Clean up any potentially sensitive data before exiting */
bzero ( slot , KEYRING_PAGE_SIZE ) ;
2012-04-11 21:24:51 +00:00
bzero ( hash , crypto_hash_sha512_BYTES ) ;
2013-10-10 03:52:20 +00:00
if ( id )
2013-03-07 03:57:33 +00:00
keyring_free_identity ( id ) ;
2013-09-06 18:33:28 +00:00
return 1 ;
2012-04-11 06:17:22 +00:00
}
2012-04-11 22:21:53 +00:00
/* Try all valid slots with the PIN and see if we find any identities with that PIN.
We might find more than one . */
2012-04-23 07:42:10 +00:00
int keyring_enter_pin ( keyring_file * k , const char * pin )
2012-04-11 22:21:53 +00:00
{
2014-10-31 03:13:23 +00:00
IN ( ) ;
2015-07-06 08:19:49 +00:00
DEBUGF ( keyring , " k=%p, pin=%s " , k , alloca_str_toprint ( pin ) ) ;
2012-04-11 22:21:53 +00:00
if ( ! pin ) pin = " " ;
2013-09-06 18:33:28 +00:00
// Check if PIN is already entered.
2014-10-31 03:13:23 +00:00
int identitiesFound = 0 ;
2014-10-31 04:30:52 +00:00
keyring_identity * id = k - > identities ;
while ( id ) {
if ( strcmp ( id - > PKRPin , pin ) = = 0 )
identitiesFound + + ;
id = id - > next ;
2013-09-06 18:33:28 +00:00
}
2014-10-31 03:13:23 +00:00
if ( identitiesFound )
RETURN ( identitiesFound ) ;
unsigned slot ;
for ( slot = 0 ; slot < k - > file_size / KEYRING_PAGE_SIZE ; slot + + ) {
/* slot zero is the BAM and salt, so skip it */
if ( slot & ( KEYRING_BAM_BITS - 1 ) ) {
/* Not a BAM slot, so examine */
2015-02-23 02:54:05 +00:00
size_t file_offset = slot * KEYRING_PAGE_SIZE ;
2014-10-31 03:13:23 +00:00
/* See if this part of the keyring file is organised */
keyring_bam * b = k - > bam ;
2015-02-23 02:54:05 +00:00
while ( b & & ( file_offset > = b - > file_offset + KEYRING_SLAB_SIZE ) )
2014-10-31 03:13:23 +00:00
b = b - > next ;
if ( ! b ) continue ;
/* Now see if slot is marked in-use. No point checking unallocated slots,
especially since the cost can be upto a second of CPU time on a phone . */
int position = slot & ( KEYRING_BAM_BITS - 1 ) ;
int byte = position > > 3 ;
int bit = position & 7 ;
if ( b - > bitmap [ byte ] & ( 1 < < bit ) ) {
/* Slot is occupied, so check it.
We have to check it for each keyring context ( ie keyring pin ) */
2014-10-31 04:30:52 +00:00
if ( keyring_decrypt_pkr ( k , pin , slot ) = = 0 )
+ + identitiesFound ;
2012-04-11 22:21:53 +00:00
}
}
2013-09-02 08:03:52 +00:00
}
2014-10-31 03:13:23 +00:00
2012-07-03 05:42:42 +00:00
RETURN ( identitiesFound ) ;
2013-02-16 17:47:24 +00:00
OUT ( ) ;
2012-04-11 22:21:53 +00:00
}
2013-09-06 18:33:28 +00:00
static unsigned test_slot ( const keyring_file * k , unsigned slot )
2013-09-03 08:01:10 +00:00
{
assert ( slot < KEYRING_BAM_BITS ) ;
unsigned position = slot & ( KEYRING_BAM_BITS - 1 ) ;
unsigned byte = position > > 3 ;
unsigned bit = position & 7 ;
return ( k - > bam - > bitmap [ byte ] & ( 1 < < bit ) ) ? 1 : 0 ;
}
static void set_slot ( keyring_file * k , unsigned slot , int bitvalue )
{
assert ( slot < KEYRING_BAM_BITS ) ;
unsigned position = slot & ( KEYRING_BAM_BITS - 1 ) ;
unsigned byte = position > > 3 ;
unsigned bit = position & 7 ;
if ( bitvalue )
k - > bam - > bitmap [ byte ] | = ( 1 < < bit ) ;
else
k - > bam - > bitmap [ byte ] & = ~ ( 1 < < bit ) ;
}
/* Find free slot in keyring. Slot 0 in any slab is the BAM and possible keyring salt, so only
* search for space in slots 1 and above . TODO : Extend to handle more than one slab !
2015-08-24 13:03:19 +00:00
* TODO : random search to avoid predictability of used slots !
2013-09-03 08:01:10 +00:00
*/
2013-09-06 18:33:28 +00:00
static unsigned find_free_slot ( const keyring_file * k )
2013-09-03 08:01:10 +00:00
{
unsigned slot ;
for ( slot = 1 ; slot < KEYRING_BAM_BITS ; + + slot )
if ( ! test_slot ( k , slot ) )
return slot ;
return 0 ;
}
2014-10-31 04:30:52 +00:00
static int keyring_commit_identity ( keyring_file * k , keyring_identity * id )
2013-09-06 18:33:28 +00:00
{
2014-10-31 03:13:23 +00:00
keypair * kp = find_keypair_sid ( id ) ;
2014-10-31 04:30:52 +00:00
keyring_identity * * i = & k - > identities ;
2014-10-31 03:13:23 +00:00
while ( * i ) {
if ( cmp_keypair ( kp , find_keypair_sid ( * i ) ) = = 0 )
2013-09-06 18:33:28 +00:00
return 0 ;
2014-10-31 03:13:23 +00:00
i = & ( * i ) - > next ;
}
2013-09-04 14:17:17 +00:00
set_slot ( k , id - > slot , 1 ) ;
2014-10-31 03:13:23 +00:00
* i = id ;
add_subscriber ( id , kp ) ;
2013-09-06 18:33:28 +00:00
return 1 ;
2013-09-04 14:17:17 +00:00
}
2013-09-05 07:04:01 +00:00
/* Create a new identity in the specified context (which supplies the keyring pin) with the
* specified PKR pin . The crypto_box and crypto_sign key pairs are automatically created , and the
* PKR is packed and written to a hithero unallocated slot which is then marked full . Requires an
* explicit call to keyring_commit ( )
2012-04-11 22:21:53 +00:00
*/
2014-10-31 04:30:52 +00:00
keyring_identity * keyring_create_identity ( keyring_file * k , const char * pin )
2012-04-11 22:21:53 +00:00
{
2015-07-06 08:19:49 +00:00
DEBUGF ( keyring , " k=%p " , k ) ;
2012-04-12 03:02:01 +00:00
/* Check obvious abort conditions early */
2012-04-12 23:55:03 +00:00
if ( ! k - > bam ) { WHY ( " keyring lacks BAM (not to be confused with KAPOW) " ) ; return NULL ; }
2012-04-12 03:02:01 +00:00
2012-04-11 22:21:53 +00:00
if ( ! pin ) pin = " " ;
2013-03-06 04:13:52 +00:00
keyring_identity * id = emalloc_zero ( sizeof ( keyring_identity ) ) ;
if ( ! id )
return NULL ;
2013-09-02 08:03:52 +00:00
/* Remember pin */
if ( ! ( id - > PKRPin = str_edup ( pin ) ) )
2012-04-11 22:21:53 +00:00
goto kci_safeexit ;
2013-09-03 08:01:10 +00:00
/* Find free slot in keyring. */
id - > slot = find_free_slot ( k ) ;
if ( id - > slot = = 0 ) {
WHY ( " no free slots in first slab (no support for more than one slab) " ) ;
2012-04-11 22:21:53 +00:00
goto kci_safeexit ;
}
/* Allocate key pairs */
2013-09-04 14:17:17 +00:00
unsigned ktype ;
for ( ktype = 1 ; ktype < NELS ( keytypes ) ; + + ktype ) {
if ( keytypes [ ktype ] . creator ) {
2014-10-31 03:13:23 +00:00
keypair * kp = keyring_alloc_keypair ( ktype , 0 ) ;
2013-09-04 14:17:17 +00:00
if ( kp = = NULL )
goto kci_safeexit ;
keytypes [ ktype ] . creator ( kp ) ;
2014-10-31 03:13:23 +00:00
keyring_identity_add_keypair ( id , kp ) ;
2013-09-04 14:17:17 +00:00
}
2012-04-12 07:31:25 +00:00
}
2014-10-31 03:13:23 +00:00
assert ( id - > keypairs ) ;
2012-04-11 22:21:53 +00:00
2013-09-04 14:17:17 +00:00
/* Mark slot as occupied and internalise new identity. */
2014-10-31 04:30:52 +00:00
keyring_commit_identity ( k , id ) ;
2013-09-03 08:01:10 +00:00
2012-08-27 00:34:59 +00:00
/* Everything went fine */
return id ;
2012-04-11 22:21:53 +00:00
kci_safeexit :
2013-09-04 14:17:17 +00:00
if ( id )
keyring_free_identity ( id ) ;
2012-04-12 23:55:03 +00:00
return NULL ;
2012-04-11 22:21:53 +00:00
}
2012-04-12 03:02:01 +00:00
int keyring_commit ( keyring_file * k )
{
2015-07-06 08:19:49 +00:00
DEBUGF ( keyring , " k=%p " , k ) ;
2013-03-07 03:57:33 +00:00
unsigned errorCount = 0 ;
2012-04-12 03:02:01 +00:00
/* Write all BAMs */
2013-03-06 04:27:23 +00:00
keyring_bam * b ;
for ( b = k - > bam ; b ; b = b - > next ) {
if ( fseeko ( k - > file , b - > file_offset , SEEK_SET ) = = - 1 ) {
WHYF_perror ( " fseeko(%d, %ld, SEEK_SET) " , fileno ( k - > file ) , ( long ) b - > file_offset ) ;
errorCount + + ;
} else if ( fwrite ( b - > bitmap , KEYRING_BAM_BYTES , 1 , k - > file ) ! = 1 ) {
WHYF_perror ( " fwrite(%p, %ld, 1, %d) " , b - > bitmap , ( long ) KEYRING_BAM_BYTES , fileno ( k - > file ) ) ;
errorCount + + ;
2014-10-31 04:30:52 +00:00
} else if ( fwrite ( k - > KeyRingSalt , k - > KeyRingSaltLen , 1 , k - > file ) ! = 1 ) {
WHYF_perror ( " fwrite(%p, %ld, 1, %d) " , k - > KeyRingSalt , ( long ) k - > KeyRingSaltLen , fileno ( k - > file ) ) ;
2013-03-06 04:27:23 +00:00
errorCount + + ;
}
2012-04-12 03:02:01 +00:00
}
/* For each identity in each context, write the record to disk.
2013-09-05 07:04:01 +00:00
This re - salts every identity as it is re - written , and the pin
2012-04-12 03:02:01 +00:00
for each identity and context is used , so changing a keypair or pin
2013-09-05 07:04:01 +00:00
is as simple as updating the keyring_identity or related structure ,
2012-04-12 03:02:01 +00:00
and then calling this function . */
2014-10-31 03:13:23 +00:00
keyring_iterator it ;
keyring_iterator_start ( k , & it ) ;
while ( keyring_next_identity ( & it ) ) {
unsigned char pkr [ KEYRING_PAGE_SIZE ] ;
if ( keyring_pack_identity ( it . identity , pkr ) )
errorCount + + ;
else {
/* Now crypt and store block */
/* Crypt */
if ( keyring_munge_block ( pkr , KEYRING_PAGE_SIZE ,
2014-10-31 04:30:52 +00:00
it . file - > KeyRingSalt , it . file - > KeyRingSaltLen ,
it . file - > KeyRingPin , it . identity - > PKRPin ) ) {
2014-10-31 03:13:23 +00:00
WHY ( " keyring_munge_block() failed " ) ;
2013-09-05 07:04:01 +00:00
errorCount + + ;
2014-10-31 03:13:23 +00:00
} else {
/* Store */
off_t file_offset = KEYRING_PAGE_SIZE * it . identity - > slot ;
if ( file_offset = = 0 ) {
2015-07-06 08:19:49 +00:00
DEBUGF ( keyring , " ID id=%p has slot=0 " , it . identity ) ;
2014-10-31 03:13:23 +00:00
} else if ( fseeko ( k - > file , file_offset , SEEK_SET ) = = - 1 ) {
WHYF_perror ( " fseeko(%d, %ld, SEEK_SET) " , fileno ( k - > file ) , ( long ) file_offset ) ;
errorCount + + ;
} else if ( fwrite ( pkr , KEYRING_PAGE_SIZE , 1 , k - > file ) ! = 1 ) {
WHYF_perror ( " fwrite(%p, %ld, 1, %d) " , pkr , ( long ) KEYRING_PAGE_SIZE , fileno ( k - > file ) ) ;
2012-04-12 03:23:37 +00:00
errorCount + + ;
2012-07-27 01:56:19 +00:00
}
2012-04-12 03:02:01 +00:00
}
2013-09-05 07:04:01 +00:00
}
}
2013-03-07 03:57:33 +00:00
if ( fflush ( k - > file ) = = - 1 ) {
WHYF_perror ( " fflush(%d) " , fileno ( k - > file ) ) ;
errorCount + + ;
}
2013-03-06 04:58:57 +00:00
return errorCount ? WHYF ( " %u errors commiting keyring to disk " , errorCount ) : 0 ;
2012-04-12 03:02:01 +00:00
}
2012-04-12 07:48:28 +00:00
2013-02-14 05:36:01 +00:00
int keyring_set_did ( keyring_identity * id , const char * did , const char * name )
2012-04-12 07:48:28 +00:00
{
/* Find where to put it */
2014-10-31 03:13:23 +00:00
keypair * kp = id - > keypairs ;
while ( kp ) {
if ( kp - > type = = KEYTYPE_DID ) {
2015-07-06 08:19:49 +00:00
DEBUG ( keyring , " Identity already contains DID " ) ;
2012-04-12 07:48:28 +00:00
break ;
2012-05-01 05:08:09 +00:00
}
2014-10-31 03:13:23 +00:00
kp = kp - > next ;
}
2012-04-12 07:48:28 +00:00
/* allocate if needed */
2014-10-31 03:13:23 +00:00
if ( ! kp ) {
if ( ( kp = keyring_alloc_keypair ( KEYTYPE_DID , 0 ) ) = = NULL )
2013-03-06 04:13:52 +00:00
return - 1 ;
2014-10-31 03:13:23 +00:00
keyring_identity_add_keypair ( id , kp ) ;
2015-07-06 08:19:49 +00:00
DEBUG ( keyring , " Created DID record for identity " ) ;
2012-04-12 07:48:28 +00:00
}
2013-12-10 06:04:35 +00:00
2012-04-12 07:48:28 +00:00
/* Store DID unpacked for ease of searching */
2013-12-10 06:04:35 +00:00
size_t len = strlen ( did ) ;
2013-10-16 03:06:52 +00:00
if ( len > 31 )
len = 31 ;
2014-10-31 03:13:23 +00:00
bcopy ( did , & kp - > private_key [ 0 ] , len ) ;
bzero ( & kp - > private_key [ len ] , 32 - len ) ;
2013-12-10 06:04:35 +00:00
len = strlen ( name ) ;
if ( len > 63 )
2013-10-16 03:06:52 +00:00
len = 63 ;
2014-10-31 03:13:23 +00:00
bcopy ( name , & kp - > public_key [ 0 ] , len ) ;
bzero ( & kp - > public_key [ len ] , 64 - len ) ;
2013-12-10 06:04:35 +00:00
2015-07-06 08:19:49 +00:00
if ( IF_DEBUG ( keyring ) ) {
dump ( " {keyring} storing did " , & kp - > private_key [ 0 ] , 32 ) ;
dump ( " {keyring} storing name " , & kp - > public_key [ 0 ] , 64 ) ;
2012-04-12 13:45:21 +00:00
}
return 0 ;
}
2013-10-24 01:13:03 +00:00
int keyring_unpack_tag ( const unsigned char * packed , size_t packed_len , const char * * name , const unsigned char * * value , size_t * length )
2013-10-16 05:42:47 +00:00
{
2013-10-24 01:13:03 +00:00
size_t i ;
2013-10-24 02:01:35 +00:00
for ( i = 0 ; i < packed_len ; i + + ) {
2013-10-24 01:13:03 +00:00
if ( packed [ i ] = = 0 ) {
* name = ( const char * ) packed ;
if ( value )
* value = & packed [ i + 1 ] ;
if ( length )
* length = packed_len - ( i + 1 ) ;
2013-10-16 05:42:47 +00:00
return 0 ;
}
}
return WHY ( " Did not find NULL values in tag " ) ;
}
2013-10-24 01:13:03 +00:00
int keyring_pack_tag ( unsigned char * packed , size_t * packed_len , const char * name , const unsigned char * value , size_t length )
{
size_t name_len = strlen ( name ) + 1 ;
if ( packed & & * packed_len < name_len + length )
return - 1 ;
* packed_len = name_len + length ;
if ( packed ) {
bcopy ( name , packed , name_len ) ;
bcopy ( value , & packed [ name_len ] , length ) ;
}
return 0 ;
}
int keyring_set_public_tag ( keyring_identity * id , const char * name , const unsigned char * value , size_t length )
2013-10-16 05:42:47 +00:00
{
2014-10-31 03:13:23 +00:00
keypair * kp = id - > keypairs ;
while ( kp ) {
2013-10-16 05:42:47 +00:00
const char * tag_name ;
const unsigned char * tag_value ;
2013-10-24 01:13:03 +00:00
size_t tag_length ;
2014-10-31 03:13:23 +00:00
if ( kp - > type = = KEYTYPE_PUBLIC_TAG & &
keyring_unpack_tag ( kp - > public_key , kp - > public_key_len ,
2013-10-24 01:13:03 +00:00
& tag_name , & tag_value , & tag_length ) = = 0 & &
2013-10-16 05:42:47 +00:00
strcmp ( tag_name , name ) = = 0 ) {
2015-07-06 08:19:49 +00:00
DEBUG ( keyring , " Found existing public tag " ) ;
2013-10-16 05:42:47 +00:00
break ;
}
2014-10-31 03:13:23 +00:00
kp = kp - > next ;
2013-10-16 05:42:47 +00:00
}
/* allocate if needed */
2014-10-31 03:13:23 +00:00
if ( ! kp ) {
2015-07-06 08:19:49 +00:00
DEBUGF ( keyring , " Creating new public tag " ) ;
2014-10-31 03:13:23 +00:00
if ( ( kp = keyring_alloc_keypair ( KEYTYPE_PUBLIC_TAG , 0 ) ) = = NULL )
2013-10-16 05:42:47 +00:00
return - 1 ;
2014-10-31 03:13:23 +00:00
keyring_identity_add_keypair ( id , kp ) ;
2013-10-16 05:42:47 +00:00
}
2014-10-31 03:13:23 +00:00
if ( kp - > public_key )
free ( kp - > public_key ) ;
2013-10-16 05:42:47 +00:00
2014-10-31 03:13:23 +00:00
if ( keyring_pack_tag ( NULL , & kp - > public_key_len , name , value , length ) )
2013-10-24 01:13:03 +00:00
return - 1 ;
2014-10-31 03:13:23 +00:00
kp - > public_key = emalloc ( kp - > public_key_len ) ;
if ( ! kp - > public_key )
2013-10-16 05:42:47 +00:00
return - 1 ;
2014-10-31 03:13:23 +00:00
if ( keyring_pack_tag ( kp - > public_key , & kp - > public_key_len , name , value , length ) )
2013-10-24 01:13:03 +00:00
return - 1 ;
2015-07-06 08:19:49 +00:00
if ( IF_DEBUG ( keyring ) )
dump ( " {keyring} New tag " , kp - > public_key , kp - > public_key_len ) ;
2013-10-16 05:42:47 +00:00
return 0 ;
}
2014-10-31 03:13:23 +00:00
keypair * keyring_find_public_tag ( keyring_iterator * it , const char * name , const unsigned char * * value , size_t * length )
2013-10-16 05:42:47 +00:00
{
2014-10-31 03:13:23 +00:00
keypair * keypair ;
while ( ( keypair = keyring_next_keytype ( it , KEYTYPE_PUBLIC_TAG ) ) ) {
2013-10-16 05:42:47 +00:00
const char * tag_name ;
2013-10-24 01:13:03 +00:00
if ( ! keyring_unpack_tag ( keypair - > public_key , keypair - > public_key_len , & tag_name , value , length ) & &
2013-10-16 05:42:47 +00:00
strcmp ( name , tag_name ) = = 0 ) {
2014-10-31 03:13:23 +00:00
return keypair ;
2013-10-16 05:42:47 +00:00
}
}
2013-10-24 01:13:03 +00:00
if ( value )
* value = NULL ;
2014-10-31 03:13:23 +00:00
return NULL ;
2013-10-16 05:42:47 +00:00
}
2014-10-31 03:13:23 +00:00
keypair * keyring_find_public_tag_value ( keyring_iterator * it , const char * name , const unsigned char * value , size_t length )
2013-10-16 05:42:47 +00:00
{
const unsigned char * stored_value ;
2013-10-24 01:13:03 +00:00
size_t stored_length ;
2014-10-31 03:13:23 +00:00
keypair * keypair ;
while ( ( keypair = keyring_find_public_tag ( it , name , & stored_value , & stored_length ) ) ) {
2013-10-16 05:42:47 +00:00
if ( stored_length = = length & & memcmp ( value , stored_value , length ) = = 0 )
2014-10-31 03:13:23 +00:00
return keypair ;
2013-10-16 03:06:52 +00:00
}
2014-10-31 03:13:23 +00:00
return NULL ;
2012-04-13 00:53:59 +00:00
}
2014-02-03 01:41:56 +00:00
struct keypair * keyring_find_sas_private ( keyring_file * k , keyring_identity * identity )
2012-04-14 17:47:36 +00:00
{
2012-06-25 23:52:51 +00:00
IN ( ) ;
2014-02-03 01:41:56 +00:00
assert ( identity ) ;
2014-10-31 03:13:23 +00:00
keypair * kp = keyring_identity_keytype ( identity , KEYTYPE_CRYPTOSIGN ) ;
2015-10-26 05:25:41 +00:00
if ( kp = = NULL ) {
WHY ( " Identity lacks SAS " ) ;
RETURN ( NULL ) ;
}
2014-02-03 01:41:56 +00:00
if ( ! kp - > verified ) {
if ( ! rhizome_verify_bundle_privatekey ( kp - > private_key , kp - > public_key ) ) {
/* SAS key is invalid (perhaps because it was a pre 0.90 format one),
so replace it */
WARN ( " SAS key is invalid -- regenerating. " ) ;
crypto_sign_edwards25519sha512batch_keypair ( kp - > public_key , kp - > private_key ) ;
keyring_commit ( k ) ;
}
kp - > verified = 1 ;
2013-10-16 03:06:52 +00:00
}
2014-02-03 01:41:56 +00:00
2015-07-06 08:19:49 +00:00
DEBUGF ( keyring , " Found SAS entry " ) ;
2014-02-03 01:41:56 +00:00
RETURN ( kp ) ;
2013-02-16 17:47:24 +00:00
OUT ( ) ;
2012-04-14 17:47:36 +00:00
}
2014-02-03 01:41:56 +00:00
static int keyring_store_sas ( struct internal_mdp_header * header , struct overlay_buffer * payload )
2013-10-09 08:24:21 +00:00
{
2014-02-03 01:41:56 +00:00
if ( header - > source - > sas_valid ) {
2015-07-06 08:19:49 +00:00
DEBUGF ( keyring , " Ignoring SID:SAS mapping for %s, already have one " , alloca_tohex_sid_t ( header - > source - > sid ) ) ;
2012-10-03 04:29:46 +00:00
return 0 ;
}
2014-02-03 01:41:56 +00:00
size_t len = ob_remaining ( payload ) ;
2012-10-03 04:29:46 +00:00
2015-07-06 08:19:49 +00:00
DEBUGF ( keyring , " Received SID:SAS mapping, %zd bytes " , len ) ;
2012-10-03 04:29:46 +00:00
2014-02-03 01:41:56 +00:00
# define SIG_BYTES crypto_sign_edwards25519sha512batch_BYTES
2012-04-14 17:47:36 +00:00
2014-02-03 01:41:56 +00:00
if ( ob_remaining ( payload ) < SAS_SIZE + SIG_BYTES )
2012-10-03 04:29:46 +00:00
return WHY ( " Truncated key mapping announcement? " ) ;
2014-02-03 01:41:56 +00:00
uint8_t plain [ len ] ;
unsigned long long plain_len = 0 ;
const uint8_t * sas_public = ob_get_bytes_ptr ( payload , SAS_SIZE ) ;
const uint8_t * compactsignature = ob_get_bytes_ptr ( payload , SIG_BYTES ) ;
size_t siglen = SID_SIZE + SIG_BYTES ;
uint8_t signature [ siglen ] ;
2012-10-03 04:29:46 +00:00
/* reconstitute signed SID for verification */
2014-02-03 01:41:56 +00:00
bcopy ( compactsignature , signature , SIG_BYTES ) ;
bcopy ( header - > source - > sid . binary , signature + SIG_BYTES , SID_SIZE ) ;
2012-10-03 04:29:46 +00:00
int r = crypto_sign_edwards25519sha512batch_open ( plain , & plain_len ,
signature , siglen ,
sas_public ) ;
2014-02-03 01:41:56 +00:00
# undef SIG_BYTES
2012-10-03 04:29:46 +00:00
if ( r )
return WHY ( " SID:SAS mapping verification signature does not verify " ) ;
/* These next two tests should never be able to fail, but let's just check anyway. */
if ( plain_len ! = SID_SIZE )
return WHY ( " SID:SAS mapping signed block is wrong length " ) ;
2014-02-03 01:41:56 +00:00
if ( memcmp ( plain , header - > source - > sid . binary , SID_SIZE ) ! = 0 )
2012-10-03 04:29:46 +00:00
return WHY ( " SID:SAS mapping signed block is for wrong SID " ) ;
/* now store it */
2014-02-03 01:41:56 +00:00
bcopy ( sas_public , header - > source - > sas_public , SAS_SIZE ) ;
header - > source - > sas_valid = 1 ;
header - > source - > sas_last_request = - 1 ;
2012-10-03 04:29:46 +00:00
2015-07-06 08:19:49 +00:00
DEBUGF ( keyring , " Stored SID:SAS mapping, SID=%s to SAS=%s " ,
alloca_tohex_sid_t ( header - > source - > sid ) ,
alloca_tohex_sas ( header - > source - > sas_public )
) ;
2012-10-03 04:29:46 +00:00
return 0 ;
}
2012-04-14 17:47:36 +00:00
2014-02-03 01:41:56 +00:00
static int keyring_respond_sas ( keyring_file * k , struct internal_mdp_header * header )
2013-10-14 03:58:48 +00:00
{
/* It's a request, so find the SAS for the SID the request was addressed to,
use that to sign that SID , and then return it in an authcrypted frame . */
2014-02-03 01:41:56 +00:00
struct keypair * kp = keyring_find_sas_private ( k , header - > destination - > identity ) ;
2013-10-14 03:58:48 +00:00
2014-02-03 01:41:56 +00:00
if ( ! kp )
2013-10-14 03:58:48 +00:00
return WHY ( " I don't have that SAS key " ) ;
2014-02-03 01:41:56 +00:00
struct internal_mdp_header response ;
bzero ( & response , sizeof response ) ;
mdp_init_response ( header , & response ) ;
uint8_t buff [ MDP_MTU ] ;
struct overlay_buffer * response_payload = ob_static ( buff , sizeof buff ) ;
ob_limitsize ( response_payload , sizeof buff ) ;
ob_append_byte ( response_payload , kp - > type ) ;
ob_append_bytes ( response_payload , kp - > public_key , kp - > public_key_len ) ;
2013-10-14 03:58:48 +00:00
unsigned long long slen ;
2014-02-03 01:41:56 +00:00
2013-10-14 03:58:48 +00:00
/* and a signature of the SID using the SAS key, to prove possession of
the key . Possession of the SID has already been established by the
decrypting of the surrounding MDP packet .
XXX - We could chop the SID out of the middle of the signed block here ,
just as we do for signed MDP packets to save 32 bytes . We won ' t worry
about doing this , however , as the mapping process is only once per session ,
not once per packet . Unless I get excited enough to do it , that is .
*/
2014-02-03 01:41:56 +00:00
if ( crypto_sign_edwards25519sha512batch ( ob_current_ptr ( response_payload ) , & slen ,
header - > destination - > sid . binary , SID_SIZE , kp - > private_key ) )
2013-10-14 03:58:48 +00:00
return WHY ( " crypto_sign() failed " ) ;
2014-02-03 01:41:56 +00:00
2013-10-14 03:58:48 +00:00
/* chop the SID from the end of the signature, since it can be reinserted on reception */
slen - = SID_SIZE ;
2014-02-03 01:41:56 +00:00
ob_append_space ( response_payload , slen ) ;
2015-07-06 08:19:49 +00:00
DEBUGF ( keyring , " Sending SID:SAS mapping, %zd bytes, %s:% " PRImdp_port_t " -> %s:% " PRImdp_port_t ,
ob_position ( response_payload ) ,
alloca_tohex_sid_t ( header - > destination - > sid ) , header - > destination_port ,
alloca_tohex_sid_t ( header - > source - > sid ) , header - > source_port
) ;
2014-02-03 01:41:56 +00:00
ob_flip ( response_payload ) ;
int ret = overlay_send_frame ( & response , response_payload ) ;
ob_free ( response_payload ) ;
return ret ;
2013-10-14 03:58:48 +00:00
}
// someone else is claiming to be me on this network
// politely request that they release my identity
int keyring_send_unlock ( struct subscriber * subscriber )
{
if ( ! subscriber - > identity )
return WHY ( " Cannot unlock an identity we don't have in our keyring " ) ;
if ( subscriber - > reachable = = REACHABLE_SELF )
return 0 ;
2014-02-03 01:41:56 +00:00
struct internal_mdp_header header ;
bzero ( & header , sizeof header ) ;
header . source = my_subscriber ;
header . destination = subscriber ;
header . source_port = MDP_PORT_KEYMAPREQUEST ;
header . destination_port = MDP_PORT_KEYMAPREQUEST ;
header . qos = OQ_MESH_MANAGEMENT ;
// use a fixed buffer so we know there's enough space for the signature
uint8_t buff [ MDP_MTU ] ;
struct overlay_buffer * response = ob_static ( buff , sizeof buff ) ;
ob_append_byte ( response , UNLOCK_REQUEST ) ;
2013-10-14 03:58:48 +00:00
2014-02-03 01:41:56 +00:00
size_t len = ob_position ( response ) ;
if ( crypto_sign_message ( subscriber - > identity , ob_ptr ( response ) , sizeof ( buff ) , & len ) )
2013-10-14 03:58:48 +00:00
return - 1 ;
2014-02-03 01:41:56 +00:00
ob_append_space ( response , len - ob_position ( response ) ) ;
2015-07-06 08:19:49 +00:00
DEBUGF ( keyring , " Sending Unlock request for sid %s " , alloca_tohex_sid_t ( subscriber - > sid ) ) ;
2014-02-03 01:41:56 +00:00
ob_flip ( response ) ;
int ret = overlay_send_frame ( & header , response ) ;
ob_free ( response ) ;
return ret ;
2013-10-14 03:58:48 +00:00
}
static int keyring_send_challenge ( struct subscriber * source , struct subscriber * dest )
{
2014-02-03 01:41:56 +00:00
struct internal_mdp_header header ;
bzero ( & header , sizeof header ) ;
2013-10-14 03:58:48 +00:00
2014-02-03 01:41:56 +00:00
header . source = source ;
header . destination = dest ;
header . source_port = MDP_PORT_KEYMAPREQUEST ;
header . destination_port = MDP_PORT_KEYMAPREQUEST ;
header . qos = OQ_MESH_MANAGEMENT ;
2013-10-14 03:58:48 +00:00
time_ms_t now = gettime_ms ( ) ;
if ( source - > identity - > challenge_expires < now ) {
source - > identity - > challenge_expires = now + 5000 ;
urandombytes ( source - > identity - > challenge , sizeof ( source - > identity - > challenge ) ) ;
}
2014-02-03 01:41:56 +00:00
struct overlay_buffer * payload = ob_new ( ) ;
ob_append_byte ( payload , UNLOCK_CHALLENGE ) ;
ob_append_bytes ( payload , source - > identity - > challenge , sizeof source - > identity - > challenge ) ;
2015-07-06 08:19:49 +00:00
DEBUGF ( keyring , " Sending Unlock challenge for sid %s " , alloca_tohex_sid_t ( source - > sid ) ) ;
2014-02-03 01:41:56 +00:00
ob_flip ( payload ) ;
int ret = overlay_send_frame ( & header , payload ) ;
ob_free ( payload ) ;
return ret ;
2013-10-14 03:58:48 +00:00
}
2014-02-03 01:41:56 +00:00
static int keyring_respond_challenge ( struct subscriber * subscriber , struct overlay_buffer * payload )
2013-10-14 03:58:48 +00:00
{
if ( ! subscriber - > identity )
return WHY ( " Cannot unlock an identity we don't have in our keyring " ) ;
if ( subscriber - > reachable = = REACHABLE_SELF )
return 0 ;
2014-02-03 01:41:56 +00:00
struct internal_mdp_header header ;
bzero ( & header , sizeof header ) ;
header . source = my_subscriber ;
header . destination = subscriber ;
header . source_port = MDP_PORT_KEYMAPREQUEST ;
header . destination_port = MDP_PORT_KEYMAPREQUEST ;
header . qos = OQ_MESH_MANAGEMENT ;
2013-10-14 03:58:48 +00:00
2014-02-03 01:41:56 +00:00
uint8_t buff [ MDP_MTU ] ;
struct overlay_buffer * response = ob_static ( buff , sizeof buff ) ;
ob_append_byte ( response , UNLOCK_RESPONSE ) ;
ob_append_bytes ( response , ob_current_ptr ( payload ) , ob_remaining ( payload ) ) ;
size_t len = ob_position ( response ) ;
if ( crypto_sign_message ( subscriber - > identity , ob_ptr ( response ) , sizeof ( buff ) , & len ) )
2013-10-14 03:58:48 +00:00
return - 1 ;
2014-02-03 01:41:56 +00:00
ob_append_space ( response , len - ob_position ( response ) ) ;
2015-07-06 08:19:49 +00:00
DEBUGF ( keyring , " Responding to Unlock challenge for sid %s " , alloca_tohex_sid_t ( subscriber - > sid ) ) ;
2014-02-03 01:41:56 +00:00
ob_flip ( response ) ;
int ret = overlay_send_frame ( & header , response ) ;
ob_free ( response ) ;
return ret ;
2013-10-14 03:58:48 +00:00
}
2014-02-03 01:41:56 +00:00
static int keyring_process_challenge ( keyring_file * k , struct subscriber * subscriber , struct overlay_buffer * payload )
2013-10-14 03:58:48 +00:00
{
time_ms_t now = gettime_ms ( ) ;
if ( subscriber - > identity - > challenge_expires < now )
return WHY ( " Identity challenge has already expired " ) ;
2014-02-03 01:41:56 +00:00
if ( ob_remaining ( payload ) ! = sizeof ( subscriber - > identity - > challenge ) )
2013-10-14 03:58:48 +00:00
return WHY ( " Challenge was not the right size " ) ;
2014-02-03 01:41:56 +00:00
if ( memcmp ( ob_current_ptr ( payload ) , subscriber - > identity - > challenge , sizeof ( subscriber - > identity - > challenge ) ) )
2013-10-14 03:58:48 +00:00
return WHY ( " Challenge failed " ) ;
keyring_release_subscriber ( k , & subscriber - > sid ) ;
return 0 ;
}
2014-02-03 01:41:56 +00:00
int keyring_mapping_request ( struct internal_mdp_header * header , struct overlay_buffer * payload )
2012-04-14 17:47:36 +00:00
{
/* The authcryption of the MDP frame proves that the SAS key is owned by the
owner of the SID , and so is absolutely compulsory . */
2014-02-03 01:41:56 +00:00
if ( header - > crypt_flags & ( MDP_NOCRYPT | MDP_NOSIGN ) )
2012-04-14 17:47:36 +00:00
return WHY ( " mapping requests must be performed under authcryption " ) ;
2013-10-14 03:58:48 +00:00
2014-02-03 01:41:56 +00:00
switch ( ob_get ( payload ) ) {
2013-10-14 03:58:48 +00:00
case KEYTYPE_CRYPTOSIGN :
2014-02-03 01:41:56 +00:00
if ( ob_remaining ( payload ) = = 0 )
return keyring_respond_sas ( keyring , header ) ;
return keyring_store_sas ( header , payload ) ;
2013-10-14 03:58:48 +00:00
break ;
case UNLOCK_REQUEST :
{
2014-02-03 01:41:56 +00:00
int len = ob_remaining ( payload ) + 1 ;
if ( crypto_verify_message ( header - > destination , ob_current_ptr ( payload ) - 1 , & len ) )
2013-10-14 03:58:48 +00:00
return WHY ( " Signature check failed " ) ;
}
2014-01-23 06:01:56 +00:00
return keyring_send_challenge ( header - > destination , header - > source ) ;
2013-10-14 03:58:48 +00:00
case UNLOCK_CHALLENGE :
2014-02-03 01:41:56 +00:00
return keyring_respond_challenge ( header - > source , payload ) ;
2013-10-14 03:58:48 +00:00
case UNLOCK_RESPONSE :
{
2014-02-03 01:41:56 +00:00
int len = ob_remaining ( payload ) + 1 ;
if ( crypto_verify_message ( header - > destination , ob_current_ptr ( payload ) - 1 , & len ) )
2013-10-14 03:58:48 +00:00
return WHY ( " Signature check failed " ) ;
2014-02-03 01:41:56 +00:00
ob_limitsize ( payload , ob_position ( payload ) + len - 1 ) ;
return keyring_process_challenge ( keyring , header - > destination , payload ) ;
2013-10-14 03:58:48 +00:00
}
2012-04-14 17:47:36 +00:00
}
return WHY ( " Not implemented " ) ;
}
2012-10-03 04:29:46 +00:00
int keyring_send_sas_request ( struct subscriber * subscriber ) {
if ( subscriber - > sas_valid )
return 0 ;
2012-08-09 02:44:32 +00:00
time_ms_t now = gettime_ms ( ) ;
2012-10-03 04:29:46 +00:00
if ( now < subscriber - > sas_last_request + 100 ) {
2015-07-06 08:19:49 +00:00
DEBUG ( keyring , " Too soon to ask for SAS mapping again " ) ;
2012-10-03 04:29:46 +00:00
return 0 ;
2012-04-14 17:47:36 +00:00
}
2012-10-03 04:29:46 +00:00
2012-09-07 03:34:40 +00:00
if ( ! my_subscriber )
2012-10-03 04:29:46 +00:00
return WHY ( " couldn't request SAS (I don't know who I am) " ) ;
2015-07-06 08:19:49 +00:00
DEBUGF ( keyring , " Requesting SAS mapping for SID=%s " , alloca_tohex_sid_t ( subscriber - > sid ) ) ;
2012-09-07 03:34:40 +00:00
2012-06-25 23:52:51 +00:00
/* request mapping (send request auth-crypted). */
2014-02-03 01:41:56 +00:00
struct internal_mdp_header header ;
bzero ( & header , sizeof header ) ;
2012-09-07 03:34:40 +00:00
2014-02-03 01:41:56 +00:00
header . source = my_subscriber ;
header . destination = subscriber ;
header . source_port = MDP_PORT_KEYMAPREQUEST ;
header . destination_port = MDP_PORT_KEYMAPREQUEST ;
header . qos = OQ_MESH_MANAGEMENT ;
2012-09-07 03:34:40 +00:00
2014-02-03 01:41:56 +00:00
struct overlay_buffer * payload = ob_new ( ) ;
ob_append_byte ( payload , KEYTYPE_CRYPTOSIGN ) ;
2012-10-03 04:29:46 +00:00
2015-07-06 08:19:49 +00:00
DEBUGF ( keyring , " Sending SAS resolution request " ) ;
2012-10-03 04:29:46 +00:00
subscriber - > sas_last_request = now ;
2014-02-03 01:41:56 +00:00
ob_flip ( payload ) ;
int ret = overlay_send_frame ( & header , payload ) ;
ob_free ( payload ) ;
return ret ;
2012-04-14 17:47:36 +00:00
}
2012-04-13 00:53:59 +00:00
2013-10-09 08:24:21 +00:00
void keyring_identity_extract ( const keyring_identity * id , const sid_t * * sidp , const char * * didp , const char * * namep )
2012-07-06 03:47:53 +00:00
{
2012-09-14 06:53:32 +00:00
int todo = ( sidp ? 1 : 0 ) | ( didp ? 2 : 0 ) | ( namep ? 4 : 0 ) ;
2014-10-31 03:13:23 +00:00
keypair * kp = id - > keypairs ;
while ( kp ) {
2012-07-06 03:47:53 +00:00
switch ( kp - > type ) {
case KEYTYPE_CRYPTOBOX :
if ( sidp )
2013-10-09 08:24:21 +00:00
* sidp = ( const sid_t * ) kp - > public_key ;
2012-07-06 03:47:53 +00:00
todo & = ~ 1 ;
break ;
case KEYTYPE_DID :
if ( didp )
* didp = ( const char * ) kp - > private_key ;
if ( namep )
* namep = ( const char * ) kp - > public_key ;
todo & = ~ 6 ;
break ;
}
2014-10-31 03:13:23 +00:00
kp = kp - > next ;
2012-07-06 03:47:53 +00:00
}
}
2012-04-12 13:45:21 +00:00
2015-02-23 02:54:05 +00:00
keyring_file * keyring_create_instance ( )
{
return keyring_open_create_instance ( " " , 1 ) ;
}
2014-10-31 04:30:52 +00:00
keyring_file * keyring_open_instance ( const char * pin )
2015-02-23 02:54:05 +00:00
{
return keyring_open_create_instance ( pin , 0 ) ;
}
static keyring_file * keyring_open_create_instance ( const char * pin , int force_create )
2012-04-12 13:45:21 +00:00
{
2012-05-19 01:08:29 +00:00
keyring_file * k = NULL ;
2012-07-03 05:42:42 +00:00
IN ( ) ;
2012-05-20 05:55:19 +00:00
if ( create_serval_instance_dir ( ) = = - 1 )
2012-07-03 05:42:42 +00:00
RETURN ( NULL ) ;
2013-08-29 08:03:39 +00:00
// Work out the absolute path to the keyring file.
2013-08-30 01:44:56 +00:00
const char * env = getenv ( " SERVALD_KEYRING_PATH " ) ;
if ( ! env )
env = " serval.keyring " ;
2012-05-20 05:55:19 +00:00
char keyringFile [ 1024 ] ;
2014-03-26 05:05:43 +00:00
if ( ! FORMF_SERVAL_ETC_PATH ( keyringFile , " %s " , env ) )
2013-08-30 01:44:56 +00:00
RETURN ( NULL ) ;
2013-08-29 08:03:39 +00:00
// Work out if the keyring file is writeable.
2013-08-30 01:44:56 +00:00
const char * readonly_env = getenv ( " SERVALD_KEYRING_READONLY " ) ;
2013-08-29 08:03:39 +00:00
bool_t readonly_b ;
2015-02-23 02:54:05 +00:00
int writeable = readonly_env = = NULL | | cf_opt_boolean ( & readonly_b , readonly_env ) ! = CFOK | | ! readonly_b ;
if ( ( k = keyring_open_or_create ( keyringFile , writeable ) ) = = NULL )
2012-07-03 05:42:42 +00:00
RETURN ( NULL ) ;
2015-02-23 02:54:05 +00:00
if ( ( force_create | | k - > file_size < KEYRING_PAGE_SIZE ) & & keyring_initialise ( k ) = = - 1 ) {
keyring_free ( k ) ;
return NULL ;
}
if ( keyring_load ( k , pin ) = = - 1 ) {
keyring_free ( k ) ;
return NULL ;
}
2013-02-13 06:19:52 +00:00
RETURN ( k ) ;
2013-02-16 17:47:24 +00:00
OUT ( ) ;
2013-02-13 06:19:52 +00:00
}
2013-02-13 07:13:24 +00:00
keyring_file * keyring_open_instance_cli ( const struct cli_parsed * parsed )
2013-02-13 06:19:52 +00:00
{
IN ( ) ;
const char * kpin = NULL ;
cli_arg ( parsed , " --keyring-pin " , & kpin , NULL , " " ) ;
2014-10-31 04:30:52 +00:00
keyring_file * k = keyring_open_instance ( kpin ) ;
if ( k = = NULL )
2014-10-31 03:13:23 +00:00
RETURN ( NULL ) ;
2013-02-13 06:19:52 +00:00
// Always open all PIN-less entries.
keyring_enter_pin ( k , " " ) ;
// Open all entries for which an entry PIN has been given.
unsigned i ;
for ( i = 0 ; i < parsed - > labelc ; + + i )
if ( strn_str_cmp ( parsed - > labelv [ i ] . label , parsed - > labelv [ i ] . len , " --entry-pin " ) = = 0 )
keyring_enter_pin ( k , parsed - > labelv [ i ] . text ) ;
2012-07-03 05:42:42 +00:00
RETURN ( k ) ;
2013-02-16 17:47:24 +00:00
OUT ( ) ;
2012-04-12 13:45:21 +00:00
}
2012-04-12 23:55:03 +00:00
/* If no identities, create an initial identity with a phone number.
This identity will not be pin protected ( initially ) . */
int keyring_seed ( keyring_file * k )
{
/* nothing to do if there is already an identity */
2014-10-31 04:30:52 +00:00
if ( k - > identities )
return 0 ;
keyring_identity * id = keyring_create_identity ( k , " " ) ;
2014-04-07 06:41:11 +00:00
if ( ! id )
return WHY ( " Could not create new identity " ) ;
if ( keyring_commit ( k ) )
return WHY ( " Could not commit new identity to keyring file " ) ;
2012-04-12 23:55:03 +00:00
return 0 ;
}
2012-04-13 16:44:41 +00:00
/*
The CryptoBox function of NaCl involves a scalar mult operation between the
public key of the recipient and the private key of the sender ( or vice versa ) .
This can take about 1 cpu second on a phone , which is rather bad .
Fortunately , NaCl allows the caching of the result of this computation , which can
then be fed into the process to make it much , much faster .
Thus we need a mechanism for caching the various scalarmult results so that they
can indeed be reused .
*/
2012-04-13 17:01:44 +00:00
/* XXX We need a more efficient implementation than a linear list, but it will
do for now . */
struct nm_record {
/* 96 bytes per record */
2013-10-09 08:24:21 +00:00
sid_t known_key ;
sid_t unknown_key ;
2012-04-13 17:01:44 +00:00
unsigned char nm_bytes [ crypto_box_curve25519xsalsa20poly1305_BEFORENMBYTES ] ;
} ;
2013-12-10 05:51:23 +00:00
unsigned nm_slots_used = 0 ;
2012-04-13 17:01:44 +00:00
/* 512 x 96 bytes = 48KB, not too big */
# define NM_CACHE_SLOTS 512
struct nm_record nm_cache [ NM_CACHE_SLOTS ] ;
2013-10-09 08:24:21 +00:00
unsigned char * keyring_get_nm_bytes ( const sid_t * known_sidp , const sid_t * unknown_sidp )
2012-04-13 16:44:41 +00:00
{
2012-06-25 23:52:51 +00:00
IN ( ) ;
2013-12-27 18:56:22 +00:00
assert ( keyring ! = NULL ) ;
2012-04-13 16:44:41 +00:00
2012-04-13 17:01:44 +00:00
/* See if we have it cached already */
2013-12-10 05:51:23 +00:00
unsigned i ;
2014-10-31 03:13:23 +00:00
for ( i = 0 ; i < nm_slots_used ; i + + ) {
if ( cmp_sid_t ( & nm_cache [ i ] . known_key , known_sidp ) ! = 0 ) continue ;
if ( cmp_sid_t ( & nm_cache [ i ] . unknown_key , unknown_sidp ) ! = 0 ) continue ;
RETURN ( nm_cache [ i ] . nm_bytes ) ;
}
2012-04-13 17:01:44 +00:00
/* Not in the cache, so prepare to cache it (or return failure if known is not
in fact a known key */
2014-10-31 03:13:23 +00:00
keyring_iterator it ;
keyring_iterator_start ( keyring , & it ) ;
2015-10-26 05:25:41 +00:00
if ( ! keyring_find_sid ( & it , known_sidp ) ) {
WHY ( " known key is not in fact known. " ) ;
RETURN ( NULL ) ;
}
2012-04-13 17:01:44 +00:00
/* work out where to store it */
if ( nm_slots_used < NM_CACHE_SLOTS ) {
i = nm_slots_used ; nm_slots_used + + ;
} else {
i = random ( ) % NM_CACHE_SLOTS ;
}
/* calculate and store */
2013-10-09 08:24:21 +00:00
nm_cache [ i ] . known_key = * known_sidp ;
nm_cache [ i ] . unknown_key = * unknown_sidp ;
2012-04-13 17:01:44 +00:00
crypto_box_curve25519xsalsa20poly1305_beforenm ( nm_cache [ i ] . nm_bytes ,
2013-10-09 08:24:21 +00:00
unknown_sidp - > binary ,
2014-10-31 03:13:23 +00:00
it . keypair - > private_key ) ;
2012-06-25 23:52:51 +00:00
RETURN ( nm_cache [ i ] . nm_bytes ) ;
2013-02-16 17:47:24 +00:00
OUT ( ) ;
2012-04-13 16:44:41 +00:00
}
2013-04-30 07:59:06 +00:00
static int cmp_identity_ptrs ( const keyring_identity * const * a , const keyring_identity * const * b )
{
2014-10-31 03:13:23 +00:00
if ( a = = b )
return 0 ;
keypair * kpa = ( * a ) - > keypairs , * kpb = ( * b ) - > keypairs ;
2013-04-30 07:59:06 +00:00
int c ;
2014-10-31 03:13:23 +00:00
while ( kpa & & kpb ) {
if ( ( c = cmp_keypair ( kpa , kpb ) ) )
2013-04-30 07:59:06 +00:00
return c ;
2014-10-31 03:13:23 +00:00
kpa = kpa - > next ;
kpb = kpb - > next ;
}
if ( kpa )
return 1 ;
if ( kpb )
return - 1 ;
return 0 ;
2013-04-30 07:59:06 +00:00
}
2013-09-03 08:01:10 +00:00
static void keyring_dump_keypair ( const keypair * kp , XPRINTF xpf , int include_secret )
{
assert ( kp - > type ! = 0 ) ;
assert ( kp - > type < NELS ( keytypes ) ) ;
xprintf ( xpf , " type=%u(%s) " , kp - > type , keytype_str ( kp - > type , " unknown " ) ) ;
if ( keytypes [ kp - > type ] . dumper )
keytypes [ kp - > type ] . dumper ( kp , xpf , include_secret ) ;
else
2013-09-05 07:04:01 +00:00
dump_private_public ( kp , xpf , include_secret ) ;
2013-09-03 08:01:10 +00:00
}
2013-04-30 07:59:06 +00:00
int keyring_dump ( keyring_file * k , XPRINTF xpf , int include_secret )
{
unsigned nids = 0 ;
2014-10-31 03:13:23 +00:00
keyring_iterator it ;
keyring_iterator_start ( k , & it ) ;
while ( keyring_next_identity ( & it ) )
2013-04-30 07:59:06 +00:00
+ + nids ;
2014-10-31 03:13:23 +00:00
2013-04-30 07:59:06 +00:00
unsigned i = 0 ;
2014-10-31 03:13:23 +00:00
const keyring_identity * idx [ nids ] ;
keyring_iterator_start ( k , & it ) ;
while ( keyring_next_identity ( & it ) ) {
2013-04-30 07:59:06 +00:00
assert ( i < nids ) ;
2014-10-31 03:13:23 +00:00
idx [ i + + ] = it . identity ;
2013-04-30 07:59:06 +00:00
}
assert ( i = = nids ) ;
2014-10-31 03:13:23 +00:00
2013-04-30 07:59:06 +00:00
qsort ( idx , nids , sizeof ( idx [ 0 ] ) , ( int ( * ) ( const void * , const void * ) ) cmp_identity_ptrs ) ;
for ( i = 0 ; i ! = nids ; + + i ) {
2014-10-31 03:13:23 +00:00
keypair * kp = idx [ i ] - > keypairs ;
while ( kp ) {
2013-09-03 08:01:10 +00:00
xprintf ( xpf , " %u: " , i ) ;
2014-10-31 03:13:23 +00:00
keyring_dump_keypair ( kp , xpf , include_secret ) ;
2013-04-30 07:59:06 +00:00
xprintf ( xpf , " \n " ) ;
2014-10-31 03:13:23 +00:00
kp = kp - > next ;
2013-04-30 07:59:06 +00:00
}
}
return 0 ;
}
2013-09-02 08:03:52 +00:00
2015-02-23 02:54:05 +00:00
int keyring_load_from_dump ( keyring_file * k , unsigned entry_pinc , const char * * entry_pinv , FILE * input )
2013-09-02 08:03:52 +00:00
{
clearerr ( input ) ;
2013-09-04 14:17:17 +00:00
char line [ 1024 ] ;
unsigned pini = 0 ;
keyring_identity * id = NULL ;
unsigned last_idn = 0 ;
while ( fgets ( line , sizeof line - 1 , input ) ! = NULL ) {
// Strip trailing \n or CRLF
size_t linelen = strlen ( line ) ;
if ( linelen & & line [ linelen - 1 ] = = ' \n ' ) {
line [ - - linelen ] = ' \0 ' ;
if ( linelen & & line [ linelen - 1 ] = = ' \r ' )
line [ - - linelen ] = ' \0 ' ;
} else
return WHY ( " line too long " ) ;
unsigned idn ;
2013-09-02 08:03:52 +00:00
unsigned ktype ;
2013-09-04 14:17:17 +00:00
int i , j ;
int n = sscanf ( line , " %u: type=%u (%n%*[^)]%n) " , & idn , & ktype , & i , & j ) ;
2013-09-02 08:03:52 +00:00
if ( n = = EOF & & ( ferror ( input ) | | feof ( input ) ) )
break ;
2013-09-04 14:17:17 +00:00
if ( n ! = 2 )
return WHYF ( " malformed input n=%u " , n ) ;
2013-09-02 08:03:52 +00:00
if ( ktype = = 0 )
2013-09-04 14:17:17 +00:00
return WHY ( " invalid input: ktype=0 " ) ;
const char * ktypestr = & line [ i ] ;
line [ j ] = ' \0 ' ;
const char * content = & line [ j + 1 ] ;
2015-07-06 08:19:49 +00:00
//DEBUGF(keyring, "n=%d i=%u ktypestr=%s j=%u content=%s", n, i, alloca_str_toprint(ktypestr), j, alloca_str_toprint(content));
2013-09-03 08:01:10 +00:00
keypair * kp = keyring_alloc_keypair ( ktype , 0 ) ;
if ( kp = = NULL )
return - 1 ;
2013-09-05 07:04:01 +00:00
int ( * loader ) ( keypair * , const char * ) = load_unknown ;
2013-09-03 08:01:10 +00:00
if ( strcmp ( ktypestr , " unknown " ) ! = 0 & & ktype < NELS ( keytypes ) )
loader = keytypes [ ktype ] . loader ;
2013-09-04 14:17:17 +00:00
if ( loader ( kp , content ) = = - 1 ) {
keyring_free_keypair ( kp ) ;
2013-09-03 08:01:10 +00:00
return - 1 ;
2013-09-04 14:17:17 +00:00
}
if ( id = = NULL | | idn ! = last_idn ) {
last_idn = idn ;
if ( id )
2014-10-31 04:30:52 +00:00
keyring_commit_identity ( k , id ) ;
2013-09-04 14:17:17 +00:00
if ( ( id = emalloc_zero ( sizeof ( keyring_identity ) ) ) = = NULL ) {
keyring_free_keypair ( kp ) ;
return - 1 ;
}
2013-09-10 01:58:55 +00:00
if ( ( id - > PKRPin = str_edup ( pini < entry_pinc ? entry_pinv [ pini + + ] : " " ) ) = = NULL ) {
2013-09-04 14:17:17 +00:00
keyring_free_keypair ( kp ) ;
keyring_free_identity ( id ) ;
return - 1 ;
}
if ( ( id - > slot = find_free_slot ( k ) ) = = 0 ) {
keyring_free_keypair ( kp ) ;
keyring_free_identity ( id ) ;
return WHY ( " no free slot " ) ;
}
}
2014-10-31 03:13:23 +00:00
if ( ! keyring_identity_add_keypair ( id , kp ) )
2013-09-03 08:01:10 +00:00
keyring_free_keypair ( kp ) ;
2013-09-02 08:03:52 +00:00
}
2013-09-04 14:17:17 +00:00
if ( id )
2014-10-31 04:30:52 +00:00
keyring_commit_identity ( k , id ) ;
2013-09-02 08:03:52 +00:00
if ( ferror ( input ) )
return WHYF_perror ( " fscanf " ) ;
return 0 ;
}