2012-04-10 03:25:46 +00:00
/*
Copyright ( C ) 2010 - 2012 Paul Gardner - Stephen , Serval Project .
This program is free software ; you can redistribute it and / or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation ; either version 2
of the License , or ( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA .
*/
2013-04-29 05:01:50 +00:00
# include <stdio.h>
2013-03-06 04:13:52 +00:00
# include <assert.h>
2013-04-29 05:01:50 +00:00
# include "constants.h"
2012-04-10 03:25:46 +00:00
# include "serval.h"
2012-11-07 06:12:45 +00:00
# include "str.h"
2013-03-06 04:13:52 +00:00
# include "mem.h"
2013-04-29 05:01:50 +00:00
# include "rotbuf.h"
2012-12-11 05:29:46 +00:00
# include "conf.h"
2012-10-18 05:16:16 +00:00
# include "rhizome.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"
# include "overlay_packet.h"
2013-10-16 03:00:00 +00:00
# include "keyring.h"
2012-04-10 03:25:46 +00:00
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_context ( keyring_context * c ) ;
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 )
{
if ( config . debug . keyring )
DEBUGF ( " opening %s in \" %s \" mode " , alloca_str_toprint ( path ) , mode ) ;
k - > file = fopen ( path , mode ) ;
if ( ! k - > file ) {
if ( errno ! = EPERM & & errno ! = ENOENT )
return WHYF_perror ( " fopen(%s, \" %s \" ) " , alloca_str_toprint(path), mode) ;
if ( config . debug . keyring )
DEBUGF ( " cannot open %s in \" %s \" mode " , alloca_str_toprint ( path ) , mode ) ;
}
return 0 ;
}
2012-04-10 03:25:46 +00:00
/*
2013-08-29 08:03:39 +00:00
* Open keyring file , read BAM and create initial context using the stored salt .
*/
keyring_file * keyring_open ( 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 ;
}
k - > file_size = ftello ( k - > file ) ;
2012-04-10 04:19:18 +00:00
if ( k - > file_size < KEYRING_PAGE_SIZE ) {
/* Uninitialised, so write 2KB of zeroes,
followed by 2 KB of random bytes as salt . */
2013-03-06 04:13:52 +00:00
if ( fseeko ( k - > file , 0 , SEEK_SET ) ) {
2013-04-30 07:59:06 +00:00
WHYF_perror ( " fseeko(%s, 0, SEEK_END) " , alloca_str_toprint ( path ) ) ;
2012-04-10 04:19:18 +00:00
keyring_free ( k ) ;
return NULL ;
}
unsigned char buffer [ KEYRING_PAGE_SIZE ] ;
bzero ( & buffer [ 0 ] , KEYRING_BAM_BYTES ) ;
2013-03-06 04:13:52 +00:00
if ( fwrite ( buffer , 2048 , 1 , k - > file ) ! = 1 ) {
2013-04-30 07:59:06 +00:00
WHYF_perror ( " fwrite(%p, 2048, 1, %s) " , buffer , alloca_str_toprint ( path ) ) ;
2013-03-06 04:13:52 +00:00
WHY ( " Could not write empty bitmap in fresh keyring file " ) ;
2012-04-10 04:19:18 +00:00
keyring_free ( k ) ;
return NULL ;
}
2012-05-19 01:08:29 +00:00
if ( urandombytes ( & buffer [ 0 ] , KEYRING_PAGE_SIZE - KEYRING_BAM_BYTES ) ) {
2013-04-30 07:59:06 +00:00
WHYF ( " Could not get random keyring salt to put in fresh keyring file %s " , path ) ;
2012-05-19 01:08:29 +00:00
keyring_free ( k ) ;
return NULL ;
}
2013-03-06 04:13:52 +00:00
if ( fwrite ( buffer , KEYRING_PAGE_SIZE - KEYRING_BAM_BYTES , 1 , k - > file ) ! = 1 ) {
2013-04-30 07:59:06 +00:00
WHYF_perror ( " fwrite(%p, %lu, 1, %s) " , buffer , ( long ) ( KEYRING_PAGE_SIZE - KEYRING_BAM_BYTES ) , alloca_str_toprint ( path ) ) ;
2013-03-06 04:13:52 +00:00
WHYF ( " Could not write keyring salt in fresh keyring file " ) ;
2012-04-10 04:19:18 +00:00
keyring_free ( k ) ;
return NULL ;
}
2012-04-12 04:30:51 +00:00
k - > file_size = KEYRING_PAGE_SIZE ;
2012-04-10 04:19:18 +00:00
}
2012-04-10 03:25:46 +00:00
/* Read BAMs for each slab in the file */
keyring_bam * * b = & k - > bam ;
off_t offset = 0 ;
while ( offset < k - > file_size ) {
/* Read bitmap from slab.
Also , if offset is zero , read the salt */
2012-05-19 01:08:29 +00:00
if ( fseeko ( k - > file , offset , SEEK_SET ) ) {
2013-04-30 07:59:06 +00:00
WHYF_perror ( " fseeko(%s, %ld, SEEK_SET) " , alloca_str_toprint ( path ) , ( long ) offset ) ;
2013-03-06 04:13:52 +00:00
WHY ( " Could not seek to BAM in keyring file " ) ;
2012-05-19 01:08:29 +00:00
keyring_free ( k ) ;
return NULL ;
}
2013-03-06 04:13:52 +00:00
* b = emalloc_zero ( sizeof ( keyring_bam ) ) ;
2012-05-19 01:08:29 +00:00
if ( ! ( * b ) ) {
2013-04-30 07:59:06 +00:00
WHYF ( " Could not allocate keyring_bam structure for key ring file %s " , path ) ;
2012-05-19 01:08:29 +00:00
keyring_free ( k ) ;
return NULL ;
}
2012-04-10 03:25:46 +00:00
( * b ) - > file_offset = offset ;
/* Read bitmap */
2013-03-06 04:13:52 +00:00
int r = fread ( ( * b ) - > bitmap , KEYRING_BAM_BYTES , 1 , k - > file ) ;
2012-05-19 01:08:29 +00:00
if ( r ! = 1 ) {
2013-04-30 07:59:06 +00:00
WHYF_perror ( " fread(%p, %ld, 1, %s) " , ( * b ) - > bitmap , ( long ) KEYRING_BAM_BYTES , alloca_str_toprint ( path ) ) ;
2013-03-06 04:13:52 +00:00
WHYF ( " Could not read BAM from keyring file " ) ;
2012-05-19 01:08:29 +00:00
keyring_free ( k ) ;
return NULL ;
}
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 ) */
2012-04-10 03:25:46 +00:00
if ( ! offset ) {
2013-03-06 04:13:52 +00:00
k - > contexts [ 0 ] = emalloc_zero ( sizeof ( keyring_context ) ) ;
2012-05-19 01:08:29 +00:00
if ( ! k - > contexts [ 0 ] ) {
2013-04-30 07:59:06 +00:00
WHYF ( " Could not allocate keyring_context for keyring file %s " , path ) ;
2012-05-19 01:08:29 +00:00
keyring_free ( k ) ;
return NULL ;
}
2013-02-13 06:19:52 +00:00
// First context is always with null keyring PIN.
2013-03-06 04:13:52 +00:00
k - > contexts [ 0 ] - > KeyRingPin = str_edup ( " " ) ;
2012-04-10 03:25:46 +00:00
k - > contexts [ 0 ] - > KeyRingSaltLen = KEYRING_PAGE_SIZE - KEYRING_BAM_BYTES ;
2013-03-06 04:13:52 +00:00
k - > contexts [ 0 ] - > KeyRingSalt = emalloc ( k - > contexts [ 0 ] - > KeyRingSaltLen ) ;
2012-05-19 01:08:29 +00:00
if ( ! k - > contexts [ 0 ] - > KeyRingSalt ) {
2013-04-30 07:59:06 +00:00
WHYF ( " Could not allocate keyring_context->salt for keyring file %s " , path ) ;
2012-05-19 01:08:29 +00:00
keyring_free ( k ) ;
return NULL ;
}
2013-03-06 04:13:52 +00:00
r = fread ( k - > contexts [ 0 ] - > KeyRingSalt , k - > contexts [ 0 ] - > KeyRingSaltLen , 1 , k - > file ) ;
2012-05-19 01:08:29 +00:00
if ( r ! = 1 ) {
2013-07-15 00:29:24 +00:00
WHYF_perror ( " fread(%p, %d, 1, %s) " , k - > contexts [ 0 ] - > KeyRingSalt , k - > contexts [ 0 ] - > KeyRingSaltLen , alloca_str_toprint ( path ) ) ;
2013-04-30 07:59:06 +00:00
WHYF ( " Could not read salt from keyring file %s " , path ) ;
2012-05-19 01:08:29 +00:00
keyring_free ( k ) ;
return NULL ;
}
2012-04-10 03:25:46 +00:00
k - > context_count = 1 ;
}
/* Skip to next slab, and find next bam pointer. */
offset + = KEYRING_PAGE_SIZE * ( KEYRING_BAM_BYTES < < 3 ) ;
b = & ( * b ) - > next ;
}
return k ;
}
2013-09-04 14:17:17 +00:00
static void add_subscriber ( keyring_identity * id , unsigned keypair )
{
assert ( keypair < id - > keypair_count ) ;
assert ( id - > keypairs [ keypair ] - > type = = KEYTYPE_CRYPTOBOX ) ;
id - > subscriber = find_subscriber ( id - > keypairs [ keypair ] - > public_key , SID_SIZE , 1 ) ;
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 ;
}
}
2012-04-10 03:25:46 +00:00
void keyring_free ( keyring_file * k )
{
int i ;
if ( ! k ) return ;
/* Close keyring file handle */
if ( k - > file ) fclose ( k - > file ) ;
k - > file = NULL ;
/* Free BAMs (no substructure, so easy) */
keyring_bam * b = k - > bam ;
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 ) ;
}
/* Free contexts (including subordinate identities and dynamically allocated salt strings).
Don ' t forget to overwrite any private data . */
for ( i = 0 ; i < KEYRING_MAX_CONTEXTS ; i + + )
if ( k - > contexts [ i ] ) {
keyring_free_context ( k - > contexts [ i ] ) ;
k - > contexts [ i ] = NULL ;
}
/* Wipe everything, just to be sure. */
bzero ( k , sizeof ( keyring_file ) ) ;
2013-11-01 01:42:37 +00:00
free ( k ) ;
2012-04-10 03:25:46 +00:00
return ;
}
2013-09-02 08:03:52 +00:00
static void wipestr ( char * str )
{
2013-09-10 03:58:27 +00:00
while ( * str )
2013-09-02 08:03:52 +00:00
* str + + = ' ' ;
}
2013-10-10 03:52:20 +00:00
void keyring_release_identity ( keyring_file * k , int cn , int id ) {
if ( config . debug . keyring )
DEBUGF ( " Releasing k=%p, cn=%d, id=%d " , k , cn , id ) ;
keyring_context * c = k - > contexts [ cn ] ;
c - > identity_count - - ;
keyring_free_identity ( c - > identities [ id ] ) ;
if ( id ! = c - > identity_count )
c - > identities [ id ] = c - > identities [ c - > identity_count ] ;
c - > identities [ c - > identity_count ] = NULL ;
if ( c - > identity_count = = 0 ) {
keyring_free_context ( c ) ;
k - > context_count - - ;
if ( cn ! = k - > context_count )
k - > contexts [ cn ] = k - > contexts [ k - > context_count ] ;
k - > contexts [ k - > context_count ] = NULL ;
}
}
2013-10-14 03:58:48 +00:00
void keyring_release_subscriber ( keyring_file * k , const sid_t * sid )
{
int cn = 0 , in = 0 , kp = 0 ;
if ( keyring_find_sid ( keyring , & cn , & in , & kp , sid )
& & keyring - > contexts [ cn ] - > identities [ in ] - > subscriber ! = my_subscriber )
keyring_release_identity ( keyring , cn , in ) ;
}
2013-10-10 03:52:20 +00:00
static void keyring_free_context ( keyring_context * c )
2012-04-10 03:25:46 +00:00
{
int i ;
if ( ! c ) return ;
if ( c - > KeyRingPin ) {
2013-09-02 08:03:52 +00:00
/* Wipe pin from local memory before freeing. */
wipestr ( c - > KeyRingPin ) ;
free ( c - > KeyRingPin ) ;
c - > KeyRingPin = NULL ;
2012-04-10 03:25:46 +00:00
}
if ( c - > KeyRingSalt ) {
bzero ( c - > KeyRingSalt , c - > KeyRingSaltLen ) ;
2013-11-01 01:42:37 +00:00
free ( c - > KeyRingSalt ) ;
2013-09-02 08:03:52 +00:00
c - > KeyRingSalt = NULL ;
c - > KeyRingSaltLen = 0 ;
2012-04-10 03:25:46 +00:00
}
/* Wipe out any loaded identities */
for ( i = 0 ; i < KEYRING_MAX_IDENTITIES ; i + + )
2013-10-10 03:52:20 +00:00
if ( c - > identities [ i ] )
keyring_free_identity ( c - > identities [ i ] ) ;
2012-04-10 03:25:46 +00:00
/* Make sure any private data is wiped out */
bzero ( c , sizeof ( keyring_context ) ) ;
2013-10-10 03:52:20 +00:00
free ( c ) ;
2012-04-10 03:25:46 +00:00
return ;
}
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
}
2013-09-02 08:03:52 +00:00
int i ;
2012-04-10 03:25:46 +00:00
for ( i = 0 ; i < PKR_MAX_KEYPAIRS ; i + + )
if ( id - > keypairs [ i ] )
keyring_free_keypair ( id - > keypairs [ i ] ) ;
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 ;
}
2013-09-10 01:58:55 +00:00
/* Create a new keyring context for the loaded keyring file. Returns the index of the context. We
* don ' t need to load any identities etc , as that happens when we enter an identity pin . If the pin
* is NULL , it is assumed to be blank . The pin does NOT have to be numeric , and has no practical
* length limitation , as it is used as an input into a hashing function . But for sanity sake , let ' s
* limit it to 16 KB .
*/
2013-02-13 06:19:52 +00:00
int keyring_enter_keyringpin ( keyring_file * k , const char * pin )
2012-04-10 04:19:18 +00:00
{
2013-03-06 03:45:27 +00:00
if ( config . debug . keyring )
2013-09-09 05:11:10 +00:00
DEBUGF ( " k=%p pin=%s " , k , alloca_str_toprint ( pin ) ) ;
2013-09-05 07:04:01 +00:00
if ( ! k )
return WHY ( " k is null " ) ;
if ( k - > context_count > = KEYRING_MAX_CONTEXTS )
2012-04-10 04:19:18 +00:00
return WHY ( " Too many loaded contexts already " ) ;
2013-09-05 07:04:01 +00:00
if ( k - > context_count < 1 )
2012-04-10 04:19:18 +00:00
return WHY ( " Cannot enter PIN without keyring salt being available " ) ;
2013-02-13 06:19:52 +00:00
int cn ;
for ( cn = 0 ; cn < k - > context_count ; + + cn )
if ( strcmp ( k - > contexts [ cn ] - > KeyRingPin , pin ) = = 0 )
2013-09-10 01:58:55 +00:00
return cn ;
2013-09-05 07:04:01 +00:00
keyring_context * c = emalloc_zero ( sizeof ( keyring_context ) ) ;
if ( c = = NULL )
return - 1 ;
/* Store pin and copy salt from the zeroeth context */
c - > KeyRingSaltLen = k - > contexts [ 0 ] - > KeyRingSaltLen ;
if ( ( ( c - > KeyRingPin = str_edup ( pin ? pin : " " ) ) = = NULL )
| | ( ( c - > KeyRingSalt = emalloc ( c - > KeyRingSaltLen ) ) = = NULL )
) {
keyring_free_context ( c ) ;
return - 1 ;
2012-04-10 04:19:18 +00:00
}
2013-09-05 07:04:01 +00:00
bcopy ( k - > contexts [ 0 ] - > KeyRingSalt , c - > KeyRingSalt , c - > KeyRingSaltLen ) ;
2013-09-10 01:58:55 +00:00
k - > contexts [ k - > context_count ] = c ;
return k - > context_count + + ;
2012-04-10 04:19:18 +00:00
}
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
{
2013-09-05 07:04:01 +00:00
if ( config . debug . keyring )
DEBUGF ( " 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-10-16 03:11:20 +00:00
int ( * unpacker ) ( keypair * , struct rotbuf * , int ) ;
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-10-16 03:11:20 +00:00
static int unpack_private_public ( keypair * kp , struct rotbuf * rb , int key_length )
2013-04-29 05:01:50 +00:00
{
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-10-16 03:11:20 +00:00
static int unpack_private_only ( keypair * kp , struct rotbuf * rb , int 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-10-16 05:42:47 +00:00
static int unpack_public_only ( keypair * kp , struct rotbuf * rb , int key_length )
{
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-10-16 03:11:20 +00:00
static int unpack_cryptobox ( keypair * kp , struct rotbuf * rb , int key_length )
2013-04-29 05:01:50 +00:00
{
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-10-16 03:11:20 +00:00
static int unpack_did_name ( keypair * kp , struct rotbuf * rb , int 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-04-30 07:59:06 +00:00
static void dump_did_name ( const keypair * kp , XPRINTF xpf , int include_secret )
{
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 ) ;
unsigned kp ;
for ( kp = 0 ; kp < id - > keypair_count & & ! rbuf . wrap ; + + kp ) {
unsigned ktype = id - > keypairs [ 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 ) {
keypair_len = id - > keypairs [ kp ] - > private_key_len + id - > keypairs [ kp ] - > public_key_len ;
}
2013-09-02 08:03:52 +00:00
} else {
packer = pack_private_only ;
keypair_len = id - > keypairs [ 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 {
if ( config . debug . keyring )
2013-09-03 08:01:10 +00:00
DEBUGF ( " 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 ;
if ( packer ( id - > keypairs [ kp ] , & rbuf ) ! = 0 )
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
}
}
// Final byte is a zero key type code.
rotbuf_putc ( & rbuf , 0x00 ) ;
if ( rbuf . wrap > 1 ) {
WHY ( " slot overrun " ) ;
goto scram ;
}
if ( kp < id - > keypair_count ) {
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 )
{
int c = a - > type < b - > type ? - 1 : a - > type > b - > type ? 1 : 0 ;
if ( c = = 0 & & a - > public_key_len ) {
assert ( a - > public_key ! = NULL ) ;
assert ( b - > public_key ! = NULL ) ;
2013-10-16 05:42:47 +00:00
int len = a - > public_key_len ;
if ( len > b - > public_key_len )
len = b - > public_key_len ;
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 ;
2013-04-30 07:59:06 +00:00
}
if ( c = = 0 & & a - > private_key_len ) {
assert ( a - > private_key ! = NULL ) ;
assert ( b - > private_key ! = NULL ) ;
2013-10-16 05:42:47 +00:00
int len = a - > private_key_len ;
if ( len > b - > private_key_len )
len = b - > private_key_len ;
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 ;
2013-04-30 07:59:06 +00:00
}
return c ;
}
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 )
{
assert ( id - > keypair_count < PKR_MAX_KEYPAIRS ) ;
assert ( kp ! = NULL ) ;
int c = 1 ;
unsigned i = 0 ;
for ( i = 0 ; i < id - > keypair_count & & ( c = cmp_keypair ( id - > keypairs [ i ] , kp ) ) < 0 ; + + i )
2013-09-06 18:33:28 +00:00
if ( i )
assert ( cmp_keypair ( id - > keypairs [ i - 1 ] , id - > keypairs [ i ] ) < 0 ) ;
2013-09-03 08:01:10 +00:00
if ( c = = 0 )
return 0 ; // duplicate not inserted
unsigned j ;
for ( j = id - > keypair_count + + ; j > i ; - - j )
id - > keypairs [ j ] = id - > keypairs [ j - 1 ] ;
id - > keypairs [ i ] = kp ;
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-23 08:43:01 +00:00
if ( id - > keypair_count > = PKR_MAX_KEYPAIRS ) {
2013-04-29 05:01:50 +00:00
WHY ( " too many key pairs " ) ;
2013-04-23 08:43:01 +00:00
keyring_free_identity ( id ) ;
return NULL ;
}
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 ) ) {
if ( config . debug . keyring )
2013-09-09 02:39:40 +00:00
DEBUGF ( " 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 ) {
if ( config . debug . keyring )
2013-09-03 08:01:10 +00:00
DEBUGF ( " 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.
if ( config . debug . keyring )
DEBUGF ( " key type 0x%02x does not unpack " , ktype ) ;
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.
2013-04-30 07:59:06 +00:00
if ( config . debug . keyring )
2013-09-03 08:01:10 +00:00
DEBUGF ( " key type 0x%02x unpacked wrong length (unpacked %u, expecting %u) " , ktype , ( int ) unpacked , ( int ) keypair_len ) ;
keyring_free_keypair ( kp ) ;
2013-04-29 05:01:50 +00:00
keyring_free_identity ( id ) ;
return NULL ;
}
} else {
2013-04-30 07:59:06 +00:00
if ( config . debug . keyring )
2013-09-03 08:01:10 +00:00
DEBUGF ( " unsupported key type 0x%02x at offset %u, reading %u bytes as private key " , ktype , ( unsigned ) rotbuf_position ( & rbo ) , ( unsigned ) kp - > private_key_len ) ;
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 ) {
2013-04-30 07:59:06 +00:00
if ( config . debug . keyring )
DEBUGF ( " slot overrun by %u bytes " , rbuf . wrap - 1 ) ;
2013-04-23 08:43:01 +00:00
keyring_free_identity ( id ) ;
return NULL ;
}
2013-04-30 07:59:06 +00:00
if ( config . debug . keyring )
DEBUGF ( " unpacked %d key pairs " , id - > keypair_count ) ;
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 ) ;
2013-09-06 18:33:28 +00:00
if ( id - > keypair_count = = 0 | | id - > keypairs [ 0 ] - > type ! = KEYTYPE_CRYPTOBOX )
2013-09-05 07:04:01 +00:00
return WHY ( " first keypair is not type CRYPTOBOX " ) ;
2013-03-06 03:32:33 +00:00
APPEND ( id - > keypairs [ 0 ] - > private_key , id - > keypairs [ 0 ] - > private_key_len ) ;
APPEND ( id - > keypairs [ 0 ] - > public_key , id - > keypairs [ 0 ] - > public_key_len ) ;
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 .
*/
2013-09-09 05:11:10 +00:00
static int keyring_decrypt_pkr ( keyring_file * k , unsigned cn , const char * pin , int slot_number )
2012-04-11 06:17:22 +00:00
{
2013-09-09 05:11:10 +00:00
if ( config . debug . keyring )
DEBUGF ( " k=%p, cn=%u pin=%s slot_number=%d " , k , cn , alloca_str_toprint ( pin ) , slot_number ) ;
assert ( cn < k - > context_count ) ;
keyring_context * cx = k - > contexts [ cn ] ;
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. */
2013-09-09 05:11:10 +00:00
if ( keyring_munge_block ( slot , KEYRING_PAGE_SIZE , cx - > KeyRingSalt , cx - > KeyRingSaltLen , cx - > 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. */
2013-04-30 07:59:06 +00:00
if ( config . debug . keyring )
DEBUGF ( " unpack slot %u " , slot_number ) ;
if ( ( ( id = keyring_unpack_identity ( slot , pin ) ) = = NULL ) | | id - > keypair_count < 1 )
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 ) ) {
2013-09-03 08:01:10 +00:00
WHYF ( " slot %u is not valid (MAC mismatch) " , slot_number ) ;
dump ( " computed " , hash , crypto_hash_sha512_BYTES ) ;
2013-09-05 07:04:01 +00:00
dump ( " stored " , & slot [ PKR_SALT_BYTES ] , crypto_hash_sha512_BYTES ) ;
2013-09-03 08:01:10 +00:00
goto kdp_safeexit ;
}
2013-09-05 07:04:01 +00:00
// Add any unlocked subscribers to our memory table, flagged as local SIDs.
2012-08-27 00:34:59 +00:00
int i = 0 ;
for ( i = 0 ; i < id - > keypair_count ; i + + ) {
2013-09-04 14:17:17 +00:00
if ( id - > keypairs [ i ] - > type = = KEYTYPE_CRYPTOBOX ) {
add_subscriber ( id , i ) ;
2012-10-10 00:02:25 +00:00
// only one key per identity supported
break ;
2012-08-27 00:34:59 +00:00
}
}
2013-09-05 07:04:01 +00:00
/* All fine, so add the id into the context and return. */
2013-09-09 05:11:10 +00:00
cx - > identities [ cx - > identity_count + + ] = 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
{
2013-03-06 03:45:27 +00:00
if ( config . debug . keyring )
DEBUGF ( " k=%p, pin=%s " , k , alloca_str_toprint ( pin ) ) ;
2012-07-03 05:42:42 +00:00
IN ( ) ;
if ( ! k ) RETURN ( - 1 ) ;
2012-04-11 22:21:53 +00:00
if ( ! pin ) pin = " " ;
2013-09-06 18:33:28 +00:00
unsigned identitiesFound = 0 ;
// Check if PIN is already entered.
{
2013-09-09 05:11:10 +00:00
unsigned cn ;
for ( cn = 0 ; cn < k - > context_count ; + + cn ) {
keyring_context * cx = k - > contexts [ cn ] ;
2013-09-06 18:33:28 +00:00
unsigned i ;
for ( i = 0 ; i < cx - > identity_count ; + + i ) {
keyring_identity * id = cx - > identities [ i ] ;
if ( strcmp ( id - > PKRPin , pin ) = = 0 )
+ + identitiesFound ;
}
}
}
// If PIN is already entered, don't enter it again.
if ( identitiesFound = = 0 ) {
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 */
off_t file_offset = slot * KEYRING_PAGE_SIZE ;
/* See if this part of the keyring file is organised */
keyring_bam * b = k - > bam ;
while ( b & & ( file_offset > = b - > file_offset + KEYRING_SLAB_SIZE ) )
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 ) */
2013-09-09 05:11:10 +00:00
int cn ;
for ( cn = 0 ; cn < k - > context_count ; + + cn )
if ( keyring_decrypt_pkr ( k , cn , pin , slot ) = = 0 )
2013-09-06 18:33:28 +00:00
+ + identitiesFound ;
}
2012-04-11 22:21:53 +00:00
}
}
2013-09-02 08:03:52 +00:00
}
2012-04-11 22:21:53 +00:00
/* Tell the caller how many identities we found */
2013-09-06 18:33:28 +00:00
if ( config . debug . keyring )
DEBUGF ( " identitiesFound=%u " , identitiesFound ) ;
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 !
*/
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 ;
}
2013-09-06 18:33:28 +00:00
static unsigned keyring_identity_keypair_sid ( const keyring_identity * id )
2013-09-04 14:17:17 +00:00
{
2013-09-06 18:33:28 +00:00
unsigned i ;
for ( i = 0 ; i < id - > keypair_count ; + + i )
if ( id - > keypairs [ i ] - > type = = KEYTYPE_CRYPTOBOX )
break ;
assert ( i < id - > keypair_count ) ;
return i ;
}
static int keyring_commit_identity ( keyring_file * k , keyring_context * cx , keyring_identity * id )
{
unsigned keypair_sid = keyring_identity_keypair_sid ( id ) ;
unsigned i ;
for ( i = 0 ; i < cx - > identity_count ; + + i )
if ( cmp_keypair ( cx - > identities [ i ] - > keypairs [ keyring_identity_keypair_sid ( cx - > identities [ i ] ) ] , id - > keypairs [ keypair_sid ] ) = = 0 )
return 0 ;
2013-09-04 14:17:17 +00:00
set_slot ( k , id - > slot , 1 ) ;
cx - > identities [ cx - > identity_count + + ] = id ;
2013-09-06 18:33:28 +00:00
add_subscriber ( id , keypair_sid ) ;
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
*/
2013-09-03 08:01:10 +00:00
keyring_identity * keyring_create_identity ( keyring_file * k , keyring_context * c , const char * pin )
2012-04-11 22:21:53 +00:00
{
2013-03-07 03:57:33 +00:00
if ( config . debug . keyring )
DEBUGF ( " 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 ) { WHY ( " keyring is NULL " ) ; return NULL ; }
if ( ! k - > bam ) { WHY ( " keyring lacks BAM (not to be confused with KAPOW) " ) ; return NULL ; }
if ( ! c ) { WHY ( " keyring context is NULL " ) ; return NULL ; }
2013-09-05 07:04:01 +00:00
if ( c - > identity_count > = KEYRING_MAX_IDENTITIES )
2012-04-12 23:55:03 +00:00
{ WHY ( " keyring context has too many identities " ) ; 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 ) {
keypair * kp = id - > keypairs [ id - > keypair_count ] = keyring_alloc_keypair ( ktype , 0 ) ;
if ( kp = = NULL )
goto kci_safeexit ;
keytypes [ ktype ] . creator ( kp ) ;
+ + id - > keypair_count ;
}
2012-04-12 07:31:25 +00:00
}
2013-09-06 18:33:28 +00:00
assert ( id - > keypair_count > 0 ) ;
2012-04-11 22:21:53 +00:00
2013-09-04 14:17:17 +00:00
/* Mark slot as occupied and internalise new identity. */
keyring_commit_identity ( k , c , 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 )
{
2013-03-06 04:27:23 +00:00
if ( config . debug . keyring )
DEBUGF ( " k=%p " , k ) ;
2013-09-05 07:04:01 +00:00
if ( ! k )
return WHY ( " keyring was NULL " ) ;
if ( k - > context_count < 1 )
return WHY ( " keyring has no contexts " ) ;
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 + + ;
} else if ( fwrite ( k - > contexts [ 0 ] - > KeyRingSalt , k - > contexts [ 0 ] - > KeyRingSaltLen , 1 , k - > file ) ! = 1 ) {
WHYF_perror ( " fwrite(%p, %ld, 1, %d) " , k - > contexts [ 0 ] - > KeyRingSalt , ( long ) k - > contexts [ 0 ] - > KeyRingSaltLen , fileno ( k - > file ) ) ;
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 . */
2013-09-05 07:04:01 +00:00
unsigned cn ;
for ( cn = 0 ; cn < k - > context_count ; + + cn ) {
if ( config . debug . keyring )
DEBUGF ( " cn = %u " , cn ) ;
const keyring_context * cx = k - > contexts [ cn ] ;
unsigned in ;
for ( in = 0 ; in < cx - > identity_count ; + + in ) {
if ( config . debug . keyring )
DEBUGF ( " in = %u " , in ) ;
const keyring_identity * id = cx - > identities [ in ] ;
unsigned char pkr [ KEYRING_PAGE_SIZE ] ;
if ( keyring_pack_identity ( id , pkr ) )
errorCount + + ;
else {
/* Now crypt and store block */
/* Crypt */
if ( keyring_munge_block ( pkr , KEYRING_PAGE_SIZE , cx - > KeyRingSalt , cx - > KeyRingSaltLen , cx - > KeyRingPin , id - > PKRPin ) ) {
WHY ( " keyring_munge_block() failed " ) ;
2012-04-12 03:23:37 +00:00
errorCount + + ;
2013-09-05 07:04:01 +00:00
} else {
/* Store */
off_t file_offset = KEYRING_PAGE_SIZE * id - > slot ;
if ( file_offset = = 0 ) {
if ( config . debug . keyring )
DEBUGF ( " ID cn=%d in=%d has slot=0 " , cn , in ) ;
} 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
{
if ( ! id ) return WHY ( " id is null " ) ;
if ( ! did ) return WHY ( " did is null " ) ;
2012-05-01 05:08:09 +00:00
if ( ! name ) name = " Mr. Smith " ;
2012-04-12 07:48:28 +00:00
/* Find where to put it */
int i ;
for ( i = 0 ; i < id - > keypair_count ; i + + )
2012-05-01 05:08:09 +00:00
if ( id - > keypairs [ i ] - > type = = KEYTYPE_DID ) {
2012-12-11 05:29:46 +00:00
if ( config . debug . keyring )
2013-09-02 08:03:52 +00:00
DEBUG ( " Identity already contains DID " ) ;
2012-04-12 07:48:28 +00:00
break ;
2012-05-01 05:08:09 +00:00
}
2013-09-02 08:03:52 +00:00
if ( i > = PKR_MAX_KEYPAIRS )
return WHY ( " Too many key pairs " ) ;
2012-04-12 07:48:28 +00:00
/* allocate if needed */
2013-09-02 08:03:52 +00:00
if ( i > = id - > keypair_count ) {
2013-09-04 14:17:17 +00:00
if ( ( id - > keypairs [ i ] = keyring_alloc_keypair ( KEYTYPE_DID , 0 ) ) = = NULL )
2013-03-06 04:13:52 +00:00
return - 1 ;
2013-09-02 08:03:52 +00:00
+ + id - > keypair_count ;
2012-12-11 05:29:46 +00:00
if ( config . debug . keyring )
2012-07-27 01:56:19 +00:00
DEBUG ( " Created DID record for identity " ) ;
2012-04-12 07:48:28 +00:00
}
/* Store DID unpacked for ease of searching */
2013-10-16 03:06:52 +00:00
int len = strlen ( did ) ;
if ( len > 31 )
len = 31 ;
2012-04-12 13:45:21 +00:00
bcopy ( did , & id - > keypairs [ i ] - > private_key [ 0 ] , len ) ;
2012-04-12 07:48:28 +00:00
bzero ( & id - > keypairs [ i ] - > private_key [ len ] , 32 - len ) ;
2013-10-16 03:06:52 +00:00
len = strlen ( name ) ;
if ( len > 63 )
len = 63 ;
2012-05-01 05:08:09 +00:00
bcopy ( name , & id - > keypairs [ i ] - > public_key [ 0 ] , len ) ;
bzero ( & id - > keypairs [ i ] - > public_key [ len ] , 64 - len ) ;
2012-04-12 07:48:28 +00:00
2012-12-11 05:29:46 +00:00
if ( config . debug . keyring ) {
2012-11-09 03:46:16 +00:00
dump ( " storing did " , & id - > keypairs [ i ] - > private_key [ 0 ] , 32 ) ;
dump ( " storing name " , & id - > keypairs [ i ] - > public_key [ 0 ] , 64 ) ;
}
2012-04-12 07:48:28 +00:00
return 0 ;
}
2013-10-16 03:00:00 +00:00
int keyring_find_did ( const keyring_file * k , int * cn , int * in , int * kp , const char * did )
2012-04-12 07:48:28 +00:00
{
2013-10-16 03:06:52 +00:00
for ( ; keyring_next_keytype ( k , cn , in , kp , KEYTYPE_DID ) ; + + ( * kp ) ) {
/* Compare DIDs */
if ( ( ! did [ 0 ] )
| | ( did [ 0 ] = = ' * ' & & did [ 1 ] = = 0 )
| | ( ! strcasecmp ( did , ( char * ) k - > contexts [ * cn ] - > identities [ * in ]
- > keypairs [ * kp ] - > private_key ) )
) {
return 1 ; // match
2013-04-30 07:59:06 +00:00
}
2012-04-12 13:45:21 +00:00
}
return 0 ;
}
2013-10-16 05:42:47 +00:00
int keyring_unpack_tag ( keypair * key , const char * * name , const unsigned char * * value , int * length )
{
int i ;
for ( i = 0 ; i < key - > public_key_len - 1 ; i + + ) {
if ( key - > public_key [ i ] = = 0 ) {
* name = ( const char * ) key - > public_key ;
* value = & key - > public_key [ i + 1 ] ;
* length = key - > public_key_len - ( i + 1 ) ;
return 0 ;
}
}
return WHY ( " Did not find NULL values in tag " ) ;
}
int keyring_set_public_tag ( keyring_identity * id , const char * name , const unsigned char * value , int length )
{
int i ;
for ( i = 0 ; i < id - > keypair_count ; i + + ) {
const char * tag_name ;
const unsigned char * tag_value ;
int tag_length ;
if ( id - > keypairs [ i ] - > type = = KEYTYPE_PUBLIC_TAG & &
keyring_unpack_tag ( id - > keypairs [ i ] , & tag_name , & tag_value , & tag_length ) = = 0 & &
strcmp ( tag_name , name ) = = 0 ) {
if ( config . debug . keyring )
DEBUG ( " Found existing public tag " ) ;
break ;
}
}
if ( i > = PKR_MAX_KEYPAIRS )
return WHY ( " Too many key pairs " ) ;
/* allocate if needed */
if ( i > = id - > keypair_count ) {
if ( config . debug . keyring )
DEBUGF ( " Creating new public tag @%d " , i ) ;
if ( ( id - > keypairs [ i ] = keyring_alloc_keypair ( KEYTYPE_PUBLIC_TAG , 0 ) ) = = NULL )
return - 1 ;
+ + id - > keypair_count ;
}
if ( id - > keypairs [ i ] - > public_key )
free ( id - > keypairs [ i ] - > public_key ) ;
int name_len = strlen ( name ) + 1 ;
id - > keypairs [ i ] - > public_key_len = name_len + length ;
id - > keypairs [ i ] - > public_key = emalloc ( id - > keypairs [ i ] - > public_key_len ) ;
if ( ! id - > keypairs [ i ] - > public_key )
return - 1 ;
bcopy ( name , id - > keypairs [ i ] - > public_key , name_len ) ;
bcopy ( value , & id - > keypairs [ i ] - > public_key [ name_len ] , length ) ;
if ( config . debug . keyring )
dump ( " New tag " , id - > keypairs [ i ] - > public_key , id - > keypairs [ i ] - > public_key_len ) ;
return 0 ;
}
int keyring_find_public_tag ( const keyring_file * k , int * cn , int * in , int * kp , const char * name , const unsigned char * * value , int * length )
{
for ( ; keyring_next_keytype ( k , cn , in , kp , KEYTYPE_PUBLIC_TAG ) ; + + ( * kp ) ) {
keypair * keypair = k - > contexts [ * cn ] - > identities [ * in ] - > keypairs [ * kp ] ;
const char * tag_name ;
if ( ! keyring_unpack_tag ( keypair , & tag_name , value , length ) & &
strcmp ( name , tag_name ) = = 0 ) {
return 1 ;
}
}
* value = NULL ;
return 0 ;
}
int keyring_find_public_tag_value ( const keyring_file * k , int * cn , int * in , int * kp , const char * name , const unsigned char * value , int length )
{
const unsigned char * stored_value ;
int stored_length ;
for ( ; keyring_find_public_tag ( k , cn , in , kp , name , & stored_value , & stored_length ) ; + + ( * kp ) ) {
if ( stored_length = = length & & memcmp ( value , stored_value , length ) = = 0 )
return 1 ;
}
return 0 ;
}
2012-06-08 08:55:43 +00:00
int keyring_identity_find_keytype ( const keyring_file * k , int cn , int in , int keytype )
2012-04-12 23:55:03 +00:00
{
2012-06-08 08:55:43 +00:00
int kp ;
for ( kp = 0 ; kp < keyring - > contexts [ cn ] - > identities [ in ] - > keypair_count ; + + kp )
if ( keyring - > contexts [ cn ] - > identities [ in ] - > keypairs [ kp ] - > type = = keytype )
return kp ;
return - 1 ;
}
2012-04-12 23:55:03 +00:00
2012-06-08 08:55:43 +00:00
int keyring_next_keytype ( const keyring_file * k , int * cn , int * in , int * kp , int keytype )
{
2013-04-30 07:59:06 +00:00
for ( ; keyring_sanitise_position ( k , cn , in , kp ) = = 0 ; + + * kp )
2012-06-08 08:55:43 +00:00
if ( k - > contexts [ * cn ] - > identities [ * in ] - > keypairs [ * kp ] - > type = = keytype )
2012-04-13 00:53:59 +00:00
return 1 ;
2012-04-12 23:55:03 +00:00
return 0 ;
}
2012-06-08 08:55:43 +00:00
int keyring_next_identity ( const keyring_file * k , int * cn , int * in , int * kp )
{
return keyring_next_keytype ( k , cn , in , kp , KEYTYPE_CRYPTOBOX ) ;
}
int keyring_sanitise_position ( const keyring_file * k , int * cn , int * in , int * kp )
2012-04-13 00:53:59 +00:00
{
2013-10-16 03:06:52 +00:00
if ( ! k )
return 1 ;
2012-04-13 00:53:59 +00:00
/* Sanity check passed in position */
2013-10-16 03:06:52 +00:00
while ( 1 ) {
if ( ( * cn ) > = k - > context_count )
return 1 ;
if ( ( * in ) > = k - > contexts [ * cn ] - > identity_count ) {
( * in ) = ( * kp ) = 0 ;
( * cn ) + + ;
continue ;
2012-04-13 00:53:59 +00:00
}
2013-10-16 03:06:52 +00:00
if ( ( * kp ) > = k - > contexts [ * cn ] - > identities [ * in ] - > keypair_count ) {
* kp = 0 ;
( * in ) + + ;
continue ;
2012-04-13 00:53:59 +00:00
}
2013-10-16 03:06:52 +00:00
return 0 ;
}
2012-04-13 00:53:59 +00:00
}
2013-10-09 08:24:21 +00:00
unsigned char * keyring_find_sas_private ( keyring_file * k , const sid_t * sidp , unsigned char * * sas_public_out )
2012-04-14 17:47:36 +00:00
{
2012-06-25 23:52:51 +00:00
IN ( ) ;
2012-04-14 17:47:36 +00:00
int cn = 0 , in = 0 , kp = 0 ;
2013-10-16 03:06:52 +00:00
if ( ! keyring_find_sid ( k , & cn , & in , & kp , sidp ) )
2012-09-05 09:23:22 +00:00
RETURNNULL ( WHYNULL ( " Could not find SID in keyring, so can't find SAS " ) ) ;
2012-04-14 17:47:36 +00:00
2013-10-16 03:06:52 +00:00
kp = keyring_identity_find_keytype ( k , cn , in , KEYTYPE_CRYPTOSIGN ) ;
if ( kp = = - 1 )
RETURNNULL ( WHYNULL ( " Identity lacks SAS " ) ) ;
unsigned char * sas_private =
k - > contexts [ cn ] - > identities [ in ] - > keypairs [ kp ] - > private_key ;
unsigned char * sas_public =
k - > contexts [ cn ] - > identities [ in ] - > keypairs [ kp ] - > public_key ;
if ( ! rhizome_verify_bundle_privatekey ( sas_private , sas_public ) ) {
/* 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 ( sas_public , sas_private ) ;
keyring_commit ( k ) ;
}
if ( config . debug . keyring )
DEBUGF ( " Found SAS entry for %s* " , alloca_tohex ( sidp - > binary , 7 ) ) ;
if ( sas_public_out ) * sas_public_out = sas_public ;
RETURN ( sas_private ) ;
2013-02-16 17:47:24 +00:00
OUT ( ) ;
2012-04-14 17:47:36 +00:00
}
2013-10-09 08:24:21 +00:00
static int keyring_store_sas ( overlay_mdp_frame * req )
{
struct subscriber * subscriber = find_subscriber ( req - > in . src . sid . binary , SID_SIZE , 1 ) ;
2012-10-03 04:29:46 +00:00
if ( subscriber - > sas_valid ) {
2012-12-11 05:29:46 +00:00
if ( config . debug . keyring )
2013-10-09 08:24:21 +00:00
DEBUGF ( " Ignoring SID:SAS mapping for %s, already have one " , alloca_tohex_sid_t ( req - > in . src . sid ) ) ;
2012-10-03 04:29:46 +00:00
return 0 ;
}
2012-12-11 05:29:46 +00:00
if ( config . debug . keyring )
2012-10-03 04:29:46 +00:00
DEBUGF ( " Received SID:SAS mapping, %d bytes " , req - > out . payload_length ) ;
unsigned keytype = req - > out . payload [ 0 ] ;
if ( keytype ! = KEYTYPE_CRYPTOSIGN )
return WHYF ( " Ignoring SID:SAS mapping with unsupported key type %u " , keytype ) ;
2012-04-14 17:47:36 +00:00
2012-10-03 04:29:46 +00:00
if ( req - > out . payload_length < 1 + SAS_SIZE )
return WHY ( " Truncated key mapping announcement? " ) ;
unsigned char plain [ req - > out . payload_length ] ;
unsigned long long plain_len = 0 ;
unsigned char * sas_public = & req - > out . payload [ 1 ] ;
unsigned char * compactsignature = & req - > out . payload [ 1 + SAS_SIZE ] ;
int siglen = SID_SIZE + crypto_sign_edwards25519sha512batch_BYTES ;
unsigned char signature [ siglen ] ;
/* reconstitute signed SID for verification */
2013-10-09 08:24:21 +00:00
bcopy ( compactsignature , signature , 64 ) ;
bcopy ( req - > out . src . sid . binary , signature + 64 , SID_SIZE ) ;
2012-10-03 04:29:46 +00:00
int r = crypto_sign_edwards25519sha512batch_open ( plain , & plain_len ,
signature , siglen ,
sas_public ) ;
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 " ) ;
2013-10-09 08:24:21 +00:00
if ( memcmp ( plain , req - > out . src . 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 */
bcopy ( sas_public , subscriber - > sas_public , SAS_SIZE ) ;
subscriber - > sas_valid = 1 ;
subscriber - > sas_last_request = - 1 ;
2012-12-11 05:29:46 +00:00
if ( config . debug . keyring )
2012-10-03 04:29:46 +00:00
DEBUGF ( " Stored SID:SAS mapping, SID=%s to SAS=%s " ,
2013-10-09 08:24:21 +00:00
alloca_tohex_sid_t ( req - > out . src . sid ) ,
2012-10-03 04:29:46 +00:00
alloca_tohex_sas ( subscriber - > sas_public )
) ;
return 0 ;
}
2012-04-14 17:47:36 +00:00
2013-10-14 03:58:48 +00:00
static int keyring_respond_sas ( keyring_file * k , overlay_mdp_frame * req )
{
/* 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 . */
unsigned char * sas_public = NULL ;
unsigned char * sas_priv = keyring_find_sas_private ( k , & req - > out . dst . sid , & sas_public ) ;
if ( ( ! sas_priv ) | | ( ! sas_public ) )
return WHY ( " I don't have that SAS key " ) ;
unsigned long long slen ;
/* type of key being verified */
req - > out . payload [ 0 ] = KEYTYPE_CRYPTOSIGN ;
/* the public key itself */
bcopy ( sas_public , & req - > out . payload [ 1 ] , SAS_SIZE ) ;
/* 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 .
*/
if ( crypto_sign_edwards25519sha512batch ( & req - > out . payload [ 1 + SAS_SIZE ] , & slen , req - > out . dst . sid . binary , SID_SIZE , sas_priv ) )
return WHY ( " crypto_sign() failed " ) ;
/* chop the SID from the end of the signature, since it can be reinserted on reception */
slen - = SID_SIZE ;
/* and record the full length of this */
req - > out . payload_length = 1 + SAS_SIZE + slen ;
overlay_mdp_swap_src_dst ( req ) ;
req - > out . ttl = 0 ;
req - > packetTypeAndFlags = MDP_TX ; /* crypt and sign */
req - > out . queue = OQ_MESH_MANAGEMENT ;
if ( config . debug . keyring )
DEBUGF ( " Sending SID:SAS mapping, %d bytes, %s:% " PRImdp_port_t " -> %s:% " PRImdp_port_t ,
req - > out . payload_length ,
alloca_tohex_sid_t ( req - > out . src . sid ) , req - > out . src . port ,
alloca_tohex_sid_t ( req - > out . dst . sid ) , req - > out . dst . port
) ;
return overlay_mdp_dispatch ( req , 0 , NULL , 0 ) ;
}
// 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 ;
overlay_mdp_frame mdp ;
memset ( & mdp , 0 , sizeof ( overlay_mdp_frame ) ) ;
mdp . packetTypeAndFlags = MDP_TX ;
mdp . out . queue = OQ_MESH_MANAGEMENT ;
mdp . out . dst . sid = subscriber - > sid ;
mdp . out . dst . port = MDP_PORT_KEYMAPREQUEST ;
mdp . out . src . port = MDP_PORT_KEYMAPREQUEST ;
mdp . out . src . sid = my_subscriber - > sid ;
mdp . out . payload [ 0 ] = UNLOCK_REQUEST ;
int len = 1 ;
if ( crypto_sign_message ( subscriber , mdp . out . payload , sizeof ( mdp . out . payload ) , & len ) )
return - 1 ;
mdp . out . payload_length = len ;
return overlay_mdp_dispatch ( & mdp , 0 /* system generated */ , NULL , 0 ) ;
}
static int keyring_send_challenge ( struct subscriber * source , struct subscriber * dest )
{
overlay_mdp_frame mdp ;
memset ( & mdp , 0 , sizeof ( overlay_mdp_frame ) ) ;
mdp . packetTypeAndFlags = MDP_TX ;
mdp . out . queue = OQ_MESH_MANAGEMENT ;
mdp . out . dst . sid = dest - > sid ;
mdp . out . dst . port = MDP_PORT_KEYMAPREQUEST ;
mdp . out . src . port = MDP_PORT_KEYMAPREQUEST ;
mdp . out . src . sid = source - > sid ;
mdp . out . payload_length = 1 ;
mdp . out . payload [ 0 ] = UNLOCK_CHALLENGE ;
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 ) ) ;
}
bcopy ( source - > identity - > challenge , & mdp . out . payload [ 1 ] , sizeof ( source - > identity - > challenge ) ) ;
mdp . out . payload_length + = sizeof ( source - > identity - > challenge ) ;
return overlay_mdp_dispatch ( & mdp , 0 /* system generated */ , NULL , 0 ) ;
}
static int keyring_respond_challenge ( struct subscriber * subscriber , overlay_mdp_frame * req )
{
if ( ! subscriber - > identity )
return WHY ( " Cannot unlock an identity we don't have in our keyring " ) ;
if ( subscriber - > reachable = = REACHABLE_SELF )
return 0 ;
overlay_mdp_frame mdp ;
memset ( & mdp , 0 , sizeof ( overlay_mdp_frame ) ) ;
mdp . packetTypeAndFlags = MDP_TX ;
mdp . out . queue = OQ_MESH_MANAGEMENT ;
mdp . out . dst . sid = subscriber - > sid ;
mdp . out . dst . port = MDP_PORT_KEYMAPREQUEST ;
mdp . out . src . port = MDP_PORT_KEYMAPREQUEST ;
mdp . out . src . sid = my_subscriber - > sid ;
mdp . out . payload [ 0 ] = UNLOCK_RESPONSE ;
bcopy ( & req - > out . payload [ 1 ] , & mdp . out . payload [ 1 ] , req - > out . payload_length - 1 ) ;
int len = req - > out . payload_length ;
if ( crypto_sign_message ( subscriber , mdp . out . payload , sizeof ( mdp . out . payload ) , & len ) )
return - 1 ;
mdp . out . payload_length = len ;
return overlay_mdp_dispatch ( & mdp , 0 /* system generated */ , NULL , 0 ) ;
}
static int keyring_process_challenge ( keyring_file * k , struct subscriber * subscriber , overlay_mdp_frame * req )
{
time_ms_t now = gettime_ms ( ) ;
if ( subscriber - > identity - > challenge_expires < now )
return WHY ( " Identity challenge has already expired " ) ;
if ( req - > out . payload_length - 1 ! = sizeof ( subscriber - > identity - > challenge ) )
return WHY ( " Challenge was not the right size " ) ;
if ( memcmp ( & req - > out . payload [ 1 ] , subscriber - > identity - > challenge , sizeof ( subscriber - > identity - > challenge ) ) )
return WHY ( " Challenge failed " ) ;
keyring_release_subscriber ( k , & subscriber - > sid ) ;
return 0 ;
}
int keyring_mapping_request ( keyring_file * k , struct overlay_frame * frame , overlay_mdp_frame * req )
2012-04-14 17:47:36 +00:00
{
if ( ! k ) return WHY ( " keyring is null " ) ;
if ( ! req ) return WHY ( " req is null " ) ;
/* The authcryption of the MDP frame proves that the SAS key is owned by the
owner of the SID , and so is absolutely compulsory . */
2012-04-15 20:36:43 +00:00
if ( req - > packetTypeAndFlags & ( 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
switch ( req - > out . payload [ 0 ] ) {
case KEYTYPE_CRYPTOSIGN :
if ( req - > out . payload_length = = 1 )
return keyring_respond_sas ( k , req ) ;
else
return keyring_store_sas ( req ) ;
break ;
case UNLOCK_REQUEST :
{
int len = req - > out . payload_length ;
if ( crypto_verify_message ( frame - > destination , req - > out . payload , & len ) )
return WHY ( " Signature check failed " ) ;
req - > out . payload_length = len ;
}
return keyring_send_challenge ( frame - > destination , frame - > source ) ;
case UNLOCK_CHALLENGE :
return keyring_respond_challenge ( frame - > source , req ) ;
case UNLOCK_RESPONSE :
{
int len = req - > out . payload_length ;
if ( crypto_verify_message ( frame - > destination , req - > out . payload , & len ) )
return WHY ( " Signature check failed " ) ;
req - > out . payload_length = len ;
}
return keyring_process_challenge ( k , frame - > destination , req ) ;
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 ) {
2012-12-11 05:29:46 +00:00
if ( config . debug . keyring )
2012-10-03 04:29:46 +00:00
INFO ( " Too soon to ask for SAS mapping again " ) ;
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) " ) ;
2012-12-11 05:29:46 +00:00
if ( config . debug . keyring )
2013-10-09 08:24:21 +00:00
DEBUGF ( " 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). */
2012-04-14 17:47:36 +00:00
overlay_mdp_frame mdp ;
2012-09-07 03:34:40 +00:00
memset ( & mdp , 0 , sizeof ( overlay_mdp_frame ) ) ;
2012-04-14 17:47:36 +00:00
mdp . packetTypeAndFlags = MDP_TX ;
2012-12-15 23:35:32 +00:00
mdp . out . queue = OQ_MESH_MANAGEMENT ;
2013-10-09 08:24:21 +00:00
mdp . out . dst . sid = subscriber - > sid ;
2012-04-14 17:47:36 +00:00
mdp . out . dst . port = MDP_PORT_KEYMAPREQUEST ;
mdp . out . src . port = MDP_PORT_KEYMAPREQUEST ;
2013-10-09 08:24:21 +00:00
mdp . out . src . sid = my_subscriber - > sid ;
2012-04-14 17:47:36 +00:00
mdp . out . payload_length = 1 ;
mdp . out . payload [ 0 ] = KEYTYPE_CRYPTOSIGN ;
2012-09-07 03:34:40 +00:00
2012-08-14 04:36:59 +00:00
if ( overlay_mdp_dispatch ( & mdp , 0 /* system generated */ , NULL , 0 ) )
2012-10-03 04:29:46 +00:00
return WHY ( " Failed to send SAS resolution request " ) ;
2012-12-11 05:29:46 +00:00
if ( config . debug . keyring )
2012-07-27 08:48:57 +00:00
DEBUGF ( " Dispatched SAS resolution request " ) ;
2012-10-03 04:29:46 +00:00
subscriber - > sas_last_request = now ;
return 0 ;
2012-04-14 17:47:36 +00:00
}
2012-04-13 00:53:59 +00:00
2013-10-09 08:24:21 +00:00
int keyring_find_sid ( const keyring_file * k , int * cn , int * in , int * kp , const sid_t * sidp )
2012-04-12 13:45:21 +00:00
{
2013-10-16 03:06:52 +00:00
for ( ; keyring_next_keytype ( k , cn , in , kp , KEYTYPE_CRYPTOBOX ) ; + + ( * kp ) ) {
if ( memcmp ( sidp - > binary , k - > contexts [ * cn ] - > identities [ * in ] - > keypairs [ * kp ] - > public_key , SID_SIZE ) = = 0 )
2012-07-06 03:47:53 +00:00
return 1 ;
2013-10-16 03:06:52 +00:00
}
2012-04-12 13:45:21 +00:00
return 0 ;
2012-04-12 07:48:28 +00:00
}
2012-04-12 13:45:21 +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 ) ;
2012-07-06 03:47:53 +00:00
int kpn ;
for ( kpn = 0 ; todo & & kpn < id - > keypair_count ; + + kpn ) {
keypair * kp = id - > keypairs [ kpn ] ;
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 ;
}
}
}
2012-04-12 13:45:21 +00:00
2013-02-13 06:19:52 +00:00
keyring_file * keyring_open_instance ( )
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 ] ;
2013-08-30 01:44:56 +00:00
if ( ! FORM_SERVAL_INSTANCE_PATH ( keyringFile , env ) )
RETURN ( NULL ) ;
2013-08-29 08:03:39 +00:00
// Work out if the keyring file is writeable.
int writeable = 0 ;
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 ;
if ( readonly_env = = NULL | | cf_opt_boolean ( & readonly_b , readonly_env ) ! = CFOK | | ! readonly_b )
writeable = 1 ;
2013-08-30 01:44:56 +00:00
if ( ( k = keyring_open ( keyringFile , writeable ) ) = = NULL )
2012-07-03 05:42:42 +00:00
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 ( ) ;
keyring_file * k = keyring_open_instance ( ) ;
if ( k = = NULL )
RETURN ( NULL ) ;
const char * kpin = NULL ;
cli_arg ( parsed , " --keyring-pin " , & kpin , NULL , " " ) ;
keyring_enter_keyringpin ( k , kpin ) ;
// 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 )
{
2013-03-06 03:45:27 +00:00
if ( config . debug . keyring )
DEBUGF ( " k=%p " , k ) ;
2012-04-12 23:55:03 +00:00
if ( ! k ) return WHY ( " keyring is null " ) ;
/* nothing to do if there is already an identity */
2013-09-09 05:11:10 +00:00
unsigned cn ;
for ( cn = 0 ; cn < k - > context_count ; + + cn )
if ( k - > contexts [ cn ] - > identity_count )
return 0 ;
2012-04-12 23:55:03 +00:00
int i ;
2013-02-14 05:36:01 +00:00
char did [ 65 ] ;
2012-04-12 23:55:03 +00:00
/* Securely generate random telephone number */
2013-02-14 05:36:01 +00:00
urandombytes ( ( unsigned char * ) did , 11 ) ;
2012-05-01 05:08:09 +00:00
/* Make DID start with 2 through 9, as 1 is special in many number spaces,
and 0 is commonly used for escaping to national or international dialling . */
2013-02-28 06:09:00 +00:00
did [ 0 ] = ' 2 ' + ( ( ( unsigned char ) did [ 0 ] ) % 8 ) ;
2012-04-12 23:55:03 +00:00
/* Then add 10 more digits, which is what we do in the mobile phone software */
2013-02-28 06:09:00 +00:00
for ( i = 1 ; i < 11 ; i + + ) did [ i ] = ' 0 ' + ( ( ( unsigned char ) did [ i ] ) % 10 ) ; did [ 11 ] = 0 ;
2012-04-12 23:55:03 +00:00
keyring_identity * id = keyring_create_identity ( k , k - > contexts [ 0 ] , " " ) ;
if ( ! id ) return WHY ( " Could not create new identity " ) ;
2013-02-14 05:36:01 +00:00
if ( keyring_set_did ( id , did , " " ) ) return WHY ( " Could not set DID of new identity " ) ;
2012-04-12 23:55:03 +00:00
if ( keyring_commit ( k ) ) return WHY ( " Could not commit new identity to keyring file " ) ;
2013-03-07 03:57:33 +00:00
{
2013-10-09 08:24:21 +00:00
const sid_t * sidp = NULL ;
2013-03-07 03:57:33 +00:00
const char * did = NULL ;
const char * name = NULL ;
2013-10-09 08:24:21 +00:00
keyring_identity_extract ( id , & sidp , & did , & name ) ;
2013-03-07 03:57:33 +00:00
INFOF ( " Seeded keyring with identity: did=%s name=%s sid=%s " ,
did ? did : " (null) " ,
alloca_str_toprint ( name ) ,
2013-10-09 08:24:21 +00:00
sidp ? alloca_tohex_sid_t ( * sidp ) : " (null) "
2013-03-07 03:57:33 +00:00
) ;
}
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 ] ;
} ;
int nm_slots_used = 0 ;
/* 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-10-09 08:24:21 +00:00
if ( ! known_sidp ) { RETURNNULL ( WHYNULL ( " known pub key is null " ) ) ; }
if ( ! unknown_sidp ) { RETURNNULL ( WHYNULL ( " unknown pub key is null " ) ) ; }
2012-09-05 09:23:22 +00:00
if ( ! keyring ) { RETURNNULL ( WHYNULL ( " keyring is null " ) ) ; }
2012-04-13 16:44:41 +00:00
2012-04-13 17:01:44 +00:00
int i ;
/* See if we have it cached already */
for ( i = 0 ; i < nm_slots_used ; i + + )
{
2013-10-09 08:24:21 +00:00
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 ;
2012-10-04 23:44:24 +00:00
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 */
2012-04-13 17:21:09 +00:00
int cn = 0 , in = 0 , kp = 0 ;
2013-10-09 08:24:21 +00:00
if ( ! keyring_find_sid ( keyring , & cn , & in , & kp , known_sidp ) )
2012-09-05 09:23:22 +00:00
{ RETURNNULL ( WHYNULL ( " known key is not in fact known. " ) ) ; }
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 ,
2012-04-13 17:01:44 +00:00
keyring
- > contexts [ cn ]
- > identities [ in ]
- > keypairs [ kp ] - > 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 )
{
int c ;
unsigned i ;
for ( i = 0 ; i < ( * a ) - > keypair_count & & i < ( * b ) - > keypair_count ; + + i )
if ( ( c = cmp_keypair ( ( * a ) - > keypairs [ i ] , ( * b ) - > keypairs [ i ] ) ) )
return c ;
return i = = ( * a ) - > keypair_count ? - 1 : 1 ;
}
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 )
{
int cn , in , kp ;
unsigned nids = 0 ;
for ( cn = in = kp = 0 ; keyring_sanitise_position ( k , & cn , & in , & kp ) = = 0 ; + + in )
+ + nids ;
const keyring_identity * idx [ nids ] ;
unsigned i = 0 ;
for ( cn = in = kp = 0 ; keyring_sanitise_position ( k , & cn , & in , & kp ) = = 0 ; + + in ) {
assert ( i < nids ) ;
idx [ i + + ] = k - > contexts [ cn ] - > identities [ in ] ;
}
assert ( i = = nids ) ;
qsort ( idx , nids , sizeof ( idx [ 0 ] ) , ( int ( * ) ( const void * , const void * ) ) cmp_identity_ptrs ) ;
for ( i = 0 ; i ! = nids ; + + i ) {
const keyring_identity * id = idx [ i ] ;
for ( kp = 0 ; kp < id - > keypair_count ; + + kp ) {
keypair * keyp = id - > keypairs [ kp ] ;
2013-09-03 08:01:10 +00:00
xprintf ( xpf , " %u: " , i ) ;
keyring_dump_keypair ( keyp , xpf , include_secret ) ;
2013-04-30 07:59:06 +00:00
xprintf ( xpf , " \n " ) ;
}
}
return 0 ;
}
2013-09-02 08:03:52 +00:00
2013-09-10 01:58:55 +00:00
int keyring_load ( keyring_file * k , const char * keyring_pin , unsigned entry_pinc , const char * * entry_pinv , FILE * input )
2013-09-02 08:03:52 +00:00
{
2013-09-10 01:58:55 +00:00
int cn = keyring_enter_keyringpin ( k , keyring_pin ) ;
if ( cn = = - 1 )
return - 1 ;
2013-09-04 14:17:17 +00:00
keyring_context * cx = k - > contexts [ cn ] ;
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 ] ;
//DEBUGF("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 )
keyring_commit_identity ( k , cx , id ) ;
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 " ) ;
}
}
2013-09-05 07:04:01 +00:00
if ( id - > keypair_count < PKR_MAX_KEYPAIRS ) {
if ( ! keyring_identity_add_keypair ( id , kp ) )
keyring_free_keypair ( kp ) ;
} else {
2013-09-03 08:01:10 +00:00
keyring_free_keypair ( kp ) ;
2013-09-05 07:04:01 +00:00
keyring_free_identity ( id ) ;
return WHY ( " too many key pairs " ) ;
}
2013-09-02 08:03:52 +00:00
}
2013-09-04 14:17:17 +00:00
if ( id )
keyring_commit_identity ( k , cx , id ) ;
2013-09-02 08:03:52 +00:00
if ( ferror ( input ) )
return WHYF_perror ( " fscanf " ) ;
return 0 ;
}