1127 lines
32 KiB
C
1127 lines
32 KiB
C
/*
|
|
* Host Identity Protocol
|
|
* Copyright (c) 2002-2012 the Boeing Company
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
* THE SOFTWARE.
|
|
*
|
|
* \file hitgen.c
|
|
*
|
|
* \authors Jeff Ahrenholz, <jeffrey.m.ahrenholz@boeing.com>
|
|
* Tom Henderson <thomas.r.henderson@boeing.com>
|
|
*
|
|
* \brief Generates DSA and RSA Host Identities and HIP configuration files.
|
|
*
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <openssl/bn.h>
|
|
#include <openssl/sha.h>
|
|
#include <openssl/dsa.h>
|
|
#include <openssl/rsa.h>
|
|
#include <openssl/rand.h>
|
|
#include <libxml/encoding.h>
|
|
#include <libxml/xmlIO.h>
|
|
#include <libxml/tree.h>
|
|
#include <sys/stat.h>
|
|
#include <errno.h>
|
|
#ifndef __WIN32__
|
|
#include <unistd.h>
|
|
#include <sys/wait.h> /* wait_pid() */
|
|
#include <sys/time.h> /* gettimeofday() */
|
|
#else
|
|
#include <io.h> /* access() */
|
|
#include <winsock2.h>
|
|
#include <ws2tcpip.h> /* INET6_ADDRSTRLEN */
|
|
#endif
|
|
#include <hip/hip_version.h>
|
|
#include <hip/hip_types.h>
|
|
#include <hip/hip_funcs.h>
|
|
#include <hip/hip_globals.h>
|
|
#ifdef HIP_VPLS
|
|
#include <openssl/ssl.h>
|
|
#include <openssl/crypto.h> /* OpenSSL's crypto library */
|
|
#include <openssl/bn.h> /* Big Numbers */
|
|
#include <openssl/des.h> /* 3DES support */
|
|
#include <openssl/blowfish.h> /* BLOWFISH support */
|
|
#include <openssl/aes.h> /* AES support */
|
|
#include <openssl/dsa.h> /* DSA support */
|
|
#include <openssl/dh.h> /* Diffie-Hellman contexts */
|
|
#include <openssl/sha.h> /* SHA1 algorithms */
|
|
#include <openssl/rand.h> /* RAND_seed() */
|
|
#include <openssl/err.h> /* ERR_ functions */
|
|
#include <openssl/engine.h>
|
|
#endif
|
|
|
|
/* dummy globals to fix undefined variables when building */
|
|
#ifdef __UMH__
|
|
int g_state;
|
|
int netlsp[2];
|
|
#endif
|
|
|
|
#ifdef __WIN32__
|
|
#define access _access
|
|
#define F_OK 0x00 /* test for file existence only */
|
|
#endif
|
|
|
|
/*
|
|
* These are the default bit sizes to generate.
|
|
*/
|
|
int default_sizes[] = { 1024 };
|
|
|
|
/* seed is taken from the updated Appendix 5 to
|
|
* FIPS PUB 186 and also appears in Appendix 5 to FIPS PIB 186-1 */
|
|
static unsigned char seed[20] = {
|
|
0xd5,0x01,0x4e,0x4b,0x60,0xef,0x2b,0xa8,0xb6,0x21,0x1b,0x40,
|
|
0x62,0xba,0x32,0x24,0xe0,0x42,0x7d,0xd3,
|
|
};
|
|
|
|
/* this struct is used only for passing options to generate_HI */
|
|
typedef struct _hi_options {
|
|
int type;
|
|
int bitsize;
|
|
char anon;
|
|
char incoming;
|
|
__u64 r1count;
|
|
char *name;
|
|
} hi_options;
|
|
|
|
extern struct hip_opt OPT;
|
|
|
|
int generate_HI(xmlNodePtr root_node, hi_options *opts)
|
|
{
|
|
int err;
|
|
char tmp[22], hit_hex[INET6_ADDRSTRLEN], lsi_str[INET_ADDRSTRLEN];
|
|
unsigned char *hitp;
|
|
struct sockaddr_storage hit;
|
|
struct sockaddr_in lsi;
|
|
xmlNodePtr hi;
|
|
unsigned long e;
|
|
hi_node hostid;
|
|
|
|
/* Crypto stuff */
|
|
BIO *bp;
|
|
DSA *dsa = NULL;
|
|
RSA *rsa = NULL;
|
|
|
|
printf("Generating a %d-bit %s key\n",
|
|
opts->bitsize, HI_TYPESTR(opts->type));
|
|
if (opts->bitsize < 512)
|
|
{
|
|
printf("Error: bit size too small. ");
|
|
printf("512 bits is the minimum size\n");
|
|
return(-1);
|
|
}
|
|
else if (opts->bitsize % 64)
|
|
{
|
|
printf("Error: the bit size must be a mupltiple of 64.\n");
|
|
return(-1);
|
|
}
|
|
|
|
/*
|
|
* generate the HI
|
|
*/
|
|
printf("Generating %s keys for HI...", HI_TYPESTR(opts->type));
|
|
switch (opts->type)
|
|
{
|
|
case HI_ALG_DSA:
|
|
printf("Generating DSA parameters (p,q,g)...");
|
|
dsa = DSA_generate_parameters(opts->bitsize, seed, sizeof(seed),
|
|
NULL, NULL, cb, stdout);
|
|
printf("\n");
|
|
if (dsa == NULL)
|
|
{
|
|
fprintf(stderr, "DSA_generate_parameters failed\n");
|
|
exit(1);
|
|
}
|
|
printf("Generating DSA keys for HI...");
|
|
err = DSA_generate_key(dsa);
|
|
if (err < 0)
|
|
{
|
|
fprintf(stderr, "DSA_generate_key() failed.\n");
|
|
exit(1);
|
|
}
|
|
break;
|
|
case HI_ALG_RSA:
|
|
e = HIP_RSA_DFT_EXP;
|
|
rsa = RSA_generate_key(opts->bitsize, e, cb, stdout);
|
|
if (!rsa)
|
|
{
|
|
fprintf(stderr, "RSA_generate_key() failed.\n");
|
|
exit(1);
|
|
}
|
|
break;
|
|
default:
|
|
printf("Error: generate_HI() got invalid HI type\n");
|
|
exit(1);
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* store everything in XML nodes
|
|
*/
|
|
hi = xmlNewChild(root_node, NULL, BAD_CAST "host_identity", NULL);
|
|
xmlNewProp(hi, BAD_CAST "alg", BAD_CAST HI_TYPESTR(opts->type));
|
|
sprintf(tmp, "%d", opts->type);
|
|
xmlNewProp(hi, BAD_CAST "alg_id", BAD_CAST tmp);
|
|
sprintf(tmp, "%d", opts->bitsize / 8);
|
|
xmlNewProp(hi, BAD_CAST "length", BAD_CAST tmp);
|
|
xmlNewProp(hi, BAD_CAST "anon", BAD_CAST (yesno(opts->anon)));
|
|
xmlNewProp(hi, BAD_CAST "incoming", BAD_CAST (yesno(opts->incoming)));
|
|
if (opts->r1count > 0)
|
|
{
|
|
sprintf(tmp, "%llu", opts->r1count);
|
|
xmlNewProp(hi, BAD_CAST "r1count", BAD_CAST tmp);
|
|
}
|
|
xmlNewChild(hi, NULL, BAD_CAST "name", BAD_CAST opts->name);
|
|
|
|
switch (opts->type)
|
|
{
|
|
case HI_ALG_DSA:
|
|
xmlNewChild(hi, NULL, BAD_CAST "P", BAD_CAST BN_bn2hex(dsa->p));
|
|
xmlNewChild(hi, NULL, BAD_CAST "Q", BAD_CAST BN_bn2hex(dsa->q));
|
|
xmlNewChild(hi, NULL, BAD_CAST "G", BAD_CAST BN_bn2hex(dsa->g));
|
|
xmlNewChild(hi, NULL, BAD_CAST "PUB",
|
|
BAD_CAST BN_bn2hex(dsa->pub_key));
|
|
xmlNewChild(hi, NULL,BAD_CAST "PRIV",
|
|
BAD_CAST BN_bn2hex(dsa->priv_key));
|
|
break;
|
|
case HI_ALG_RSA:
|
|
xmlNewChild(hi, NULL, BAD_CAST "N", BAD_CAST BN_bn2hex(rsa->n));
|
|
xmlNewChild(hi, NULL, BAD_CAST "E", BAD_CAST BN_bn2hex(rsa->e));
|
|
xmlNewChild(hi, NULL, BAD_CAST "D", BAD_CAST BN_bn2hex(rsa->d));
|
|
xmlNewChild(hi, NULL, BAD_CAST "P", BAD_CAST BN_bn2hex(rsa->p));
|
|
xmlNewChild(hi, NULL, BAD_CAST "Q", BAD_CAST BN_bn2hex(rsa->q));
|
|
xmlNewChild(hi, NULL, BAD_CAST "dmp1",
|
|
BAD_CAST BN_bn2hex(rsa->dmp1));
|
|
xmlNewChild(hi, NULL, BAD_CAST "dmq1",
|
|
BAD_CAST BN_bn2hex(rsa->dmq1));
|
|
xmlNewChild(hi, NULL, BAD_CAST "iqmp",
|
|
BAD_CAST BN_bn2hex(rsa->iqmp));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* calculate and store the HIT
|
|
*/
|
|
memset(&hostid, 0, sizeof(hi_node));
|
|
memset(&hit, 0, sizeof(struct sockaddr_storage));
|
|
memset(hit_hex, 0, INET6_ADDRSTRLEN);
|
|
|
|
hostid.algorithm_id = opts->type;
|
|
hostid.size = (opts->bitsize) / 8;
|
|
hostid.rsa = rsa;
|
|
hostid.dsa = dsa;
|
|
|
|
hit.ss_family = AF_INET6;
|
|
hitp = SA2IP(&hit);
|
|
if (hi_to_hit(&hostid, hitp) < 0)
|
|
{
|
|
printf("Error generating HIT!\n");
|
|
exit(1);
|
|
}
|
|
|
|
if (addr_to_str(SA(&hit), (__u8*)hit_hex, INET6_ADDRSTRLEN))
|
|
{
|
|
printf("Error generating HIT! Do you have the IPv6 protocol "
|
|
"installed?\n");
|
|
exit(1);
|
|
}
|
|
xmlNewChild(hi, NULL, BAD_CAST "HIT", BAD_CAST hit_hex);
|
|
|
|
/*
|
|
* calculate the LSI from the HIT
|
|
*/
|
|
memset(&lsi, 0, sizeof(struct sockaddr_in));
|
|
memset(lsi_str, 0, INET_ADDRSTRLEN);
|
|
lsi.sin_family = AF_INET;
|
|
lsi.sin_addr.s_addr = ntohl(HIT2LSI(hitp));
|
|
if (addr_to_str(SA(&lsi), (__u8*)lsi_str, INET_ADDRSTRLEN))
|
|
{
|
|
printf("Error generating LSI from HIT!\n");
|
|
}
|
|
xmlNewChild(hi, NULL, BAD_CAST "LSI", BAD_CAST lsi_str);
|
|
|
|
if (D_VERBOSE == OPT.debug)
|
|
{
|
|
bp = BIO_new_fp(stdout, BIO_NOCLOSE);
|
|
if (dsa)
|
|
{
|
|
DSAparams_print(bp, dsa);
|
|
}
|
|
if (rsa)
|
|
{
|
|
RSA_print(bp, rsa, 0);
|
|
}
|
|
BIO_free(bp);
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
#ifdef HIP_VPLS
|
|
int output_HI(xmlNodePtr root_node, hi_options *opts)
|
|
{
|
|
int err;
|
|
char tmp[22], hit_hex[INET6_ADDRSTRLEN], lsi_str[INET_ADDRSTRLEN];
|
|
unsigned char *hitp;
|
|
struct sockaddr_storage hit;
|
|
struct sockaddr_in lsi;
|
|
xmlNodePtr hi;
|
|
/* unsigned long e; */
|
|
hi_node hostid;
|
|
extern ENGINE *engine_init(char *);
|
|
extern SSL_CTX *ssl_ctx_init(ENGINE *e, const char *pin);
|
|
|
|
/* Crypto stuff */
|
|
BIO *bp;
|
|
DSA *dsa = NULL;
|
|
RSA *rsa = NULL;
|
|
EVP_PKEY *pkey = NULL;
|
|
char pin[12] = "123456";
|
|
ENGINE *engine = NULL;
|
|
SSL_CTX *ctx = NULL;
|
|
SSL *con = NULL;
|
|
struct {
|
|
const char * cert_id;
|
|
X509 * cert;
|
|
} parms;
|
|
|
|
printf("Generating a %d-bit %s key\n",
|
|
opts->bitsize, HI_TYPESTR(opts->type));
|
|
if (opts->bitsize < 512)
|
|
{
|
|
printf("Error: bit size too small. ");
|
|
printf("512 bits is the minimum size\n");
|
|
return(-1);
|
|
}
|
|
else if (opts->bitsize % 64)
|
|
{
|
|
printf("Error: the bit size must be a mupltiple of 64.\n");
|
|
return(-1);
|
|
}
|
|
|
|
/* TODO: If hitgen is regularly used with smartcard, the opensc engine
|
|
* and
|
|
* opensc module should be parameterized in engine_init call */
|
|
/* Initialize OpenSC engine for OpenSSL */
|
|
engine = engine_init(pin);
|
|
if (engine == NULL)
|
|
{
|
|
fprintf(stderr,"Error in engine init\n");
|
|
exit(1);
|
|
}
|
|
|
|
/* Initialize OpenSSL context, sending PIN for smartcard */
|
|
ctx = ssl_ctx_init(engine, pin);
|
|
if (ctx == NULL)
|
|
{
|
|
fprintf(stderr,"Error in ssl init, bailing...\n");
|
|
exit(1);
|
|
}
|
|
|
|
/* Initialize the OpenSSL connection */
|
|
con = SSL_new(ctx);
|
|
if (con == NULL)
|
|
{
|
|
fprintf(stderr,"Error calling SSL_new()\n");
|
|
exit(1);
|
|
}
|
|
|
|
int slot, id;
|
|
char buff[100];
|
|
/* TODO: If hitgen is regularly used with smartcard, slot and id should
|
|
* be
|
|
* parameterized */
|
|
slot = 4;
|
|
id = 45;
|
|
sprintf(buff, "%d:%d", slot, id);
|
|
parms.cert_id = buff;
|
|
parms.cert = NULL;
|
|
ENGINE_ctrl_cmd(engine, "LOAD_CERT_CTRL", 0, &parms, NULL, 1);
|
|
if (parms.cert)
|
|
{
|
|
printf("get cert - %s\n", buff);
|
|
}
|
|
|
|
pkey = SSL_get_privatekey(con);
|
|
if (pkey == NULL)
|
|
{
|
|
fprintf(stderr,"Error call SSL_get_privatekey\n");
|
|
exit(1);
|
|
}
|
|
|
|
rsa = EVP_PKEY_get1_RSA(pkey);
|
|
dsa = EVP_PKEY_get1_DSA(pkey);
|
|
|
|
/*
|
|
* generate the HI
|
|
*/
|
|
printf("Generating %s keys for HI...", HI_TYPESTR(opts->type));
|
|
if (dsa)
|
|
{
|
|
printf("Generating DSA parameters (p,q,g)...");
|
|
dsa = DSA_generate_parameters(opts->bitsize, seed, sizeof(seed),
|
|
NULL, NULL, cb, stdout);
|
|
printf("\n");
|
|
if (dsa == NULL)
|
|
{
|
|
fprintf(stderr, "DSA_generate_parameters failed\n");
|
|
exit(1);
|
|
}
|
|
printf("Generating DSA keys for HI...");
|
|
err = DSA_generate_key(dsa);
|
|
if (err < 0)
|
|
{
|
|
fprintf(stderr, "DSA_generate_key() failed.\n");
|
|
exit(1);
|
|
}
|
|
}
|
|
else if (rsa)
|
|
{
|
|
/* = HIP_RSA_DFT_EXP;
|
|
* rsa = RSA_generate_key(opts->bitsize, e, cb, stdout);
|
|
* if (!rsa) {
|
|
* fprintf(stderr, "RSA_generate_key() failed.\n");
|
|
* exit(1);
|
|
* }
|
|
*/
|
|
}
|
|
else
|
|
{
|
|
printf("Error: generate_HI() got invalid HI type\n");
|
|
exit(1);
|
|
}
|
|
|
|
/*
|
|
* store everything in XML nodes
|
|
*/
|
|
hi = xmlNewChild(root_node, NULL, BAD_CAST "host_identity", NULL);
|
|
xmlNewProp(hi, BAD_CAST "alg", BAD_CAST HI_TYPESTR(opts->type));
|
|
sprintf(tmp, "%d", opts->type);
|
|
xmlNewProp(hi, BAD_CAST "alg_id", BAD_CAST tmp);
|
|
sprintf(tmp, "%d", opts->bitsize / 8);
|
|
xmlNewProp(hi, BAD_CAST "length", BAD_CAST tmp);
|
|
xmlNewProp(hi, BAD_CAST "anon", BAD_CAST (yesno(opts->anon)));
|
|
xmlNewProp(hi, BAD_CAST "incoming", BAD_CAST (yesno(opts->incoming)));
|
|
if (opts->r1count > 0)
|
|
{
|
|
sprintf(tmp, "%llu", opts->r1count);
|
|
xmlNewProp(hi, BAD_CAST "r1count", BAD_CAST tmp);
|
|
}
|
|
xmlNewChild(hi, NULL, BAD_CAST "name", BAD_CAST opts->name);
|
|
|
|
if (dsa)
|
|
{
|
|
xmlNewChild(hi, NULL, BAD_CAST "P", BAD_CAST BN_bn2hex(dsa->p));
|
|
xmlNewChild(hi, NULL, BAD_CAST "Q", BAD_CAST BN_bn2hex(dsa->q));
|
|
xmlNewChild(hi, NULL, BAD_CAST "G", BAD_CAST BN_bn2hex(dsa->g));
|
|
xmlNewChild(hi, NULL, BAD_CAST "PUB",
|
|
BAD_CAST BN_bn2hex(dsa->pub_key));
|
|
xmlNewChild(hi, NULL,BAD_CAST "PRIV",
|
|
BAD_CAST BN_bn2hex(dsa->priv_key));
|
|
}
|
|
else if (rsa)
|
|
{
|
|
xmlNewChild(hi, NULL, BAD_CAST "N", BAD_CAST BN_bn2hex(rsa->n));
|
|
xmlNewChild(hi, NULL, BAD_CAST "E", BAD_CAST BN_bn2hex(rsa->e));
|
|
/* output public key parameters only
|
|
* xmlNewChild(hi, NULL, BAD_CAST "D", BAD_CAST
|
|
* BN_bn2hex(rsa->d));
|
|
* xmlNewChild(hi, NULL, BAD_CAST "P", BAD_CAST
|
|
* BN_bn2hex(rsa->p));
|
|
* xmlNewChild(hi, NULL, BAD_CAST "Q", BAD_CAST
|
|
* BN_bn2hex(rsa->q));
|
|
* xmlNewChild(hi, NULL, BAD_CAST "dmp1",
|
|
* BAD_CAST BN_bn2hex(rsa->dmp1));
|
|
* xmlNewChild(hi, NULL, BAD_CAST "dmq1",
|
|
* BAD_CAST BN_bn2hex(rsa->dmq1));
|
|
* xmlNewChild(hi, NULL, BAD_CAST "iqmp",
|
|
* BAD_CAST BN_bn2hex(rsa->iqmp));
|
|
*/
|
|
}
|
|
|
|
/*
|
|
* calculate and store the HIT
|
|
*/
|
|
memset(&hostid, 0, sizeof(hi_node));
|
|
memset(&hit, 0, sizeof(struct sockaddr_storage));
|
|
memset(hit_hex, 0, INET6_ADDRSTRLEN);
|
|
|
|
hostid.algorithm_id = opts->type;
|
|
hostid.size = (opts->bitsize) / 8;
|
|
hostid.rsa = rsa;
|
|
hostid.dsa = dsa;
|
|
|
|
hit.ss_family = AF_INET6;
|
|
hitp = (unsigned char*)(SA2IP(&hit));
|
|
if (hi_to_hit(&hostid, hitp) < 0)
|
|
{
|
|
printf("Error generating HIT!\n");
|
|
exit(1);
|
|
}
|
|
|
|
if (addr_to_str(SA(&hit), (__u8*)hit_hex, INET6_ADDRSTRLEN))
|
|
{
|
|
printf("Error generating HIT! Do you have the IPv6 protocol "
|
|
"installed?\n");
|
|
exit(1);
|
|
}
|
|
xmlNewChild(hi, NULL, BAD_CAST "HIT", BAD_CAST hit_hex);
|
|
|
|
/*
|
|
* calculate the LSI from the HIT
|
|
*/
|
|
memset(&lsi, 0, sizeof(struct sockaddr_in));
|
|
memset(lsi_str, 0, INET_ADDRSTRLEN);
|
|
lsi.sin_family = AF_INET;
|
|
lsi.sin_addr.s_addr = ntohl(HIT2LSI(hitp));
|
|
if (addr_to_str(SA(&lsi), (__u8*)lsi_str, INET_ADDRSTRLEN))
|
|
{
|
|
printf("Error generating LSI from HIT!\n");
|
|
}
|
|
xmlNewChild(hi, NULL, BAD_CAST "LSI", BAD_CAST lsi_str);
|
|
|
|
if (D_VERBOSE == OPT.debug)
|
|
{
|
|
bp = BIO_new_fp(stdout, BIO_NOCLOSE);
|
|
if (dsa)
|
|
{
|
|
DSAparams_print(bp, dsa);
|
|
}
|
|
if (rsa)
|
|
{
|
|
RSA_print(bp, rsa, 0);
|
|
}
|
|
BIO_free(bp);
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
#endif
|
|
|
|
/*
|
|
* Delete whitespace from an XML document, which is necessary if you
|
|
* want the document to be reformatted after reading it from a file.
|
|
*
|
|
* from:
|
|
* http://mail.gnome.org/archives/gnome-devel-list/2003-May/msg00067.html
|
|
*
|
|
*/
|
|
static void
|
|
delete_unused_whitespace_r(xmlNodePtr node)
|
|
{
|
|
xmlNodePtr next;
|
|
|
|
for (node = node->xmlChildrenNode; node; node = next)
|
|
{
|
|
next = node->next;
|
|
if (xmlIsBlankNode(node))
|
|
{
|
|
xmlUnlinkNode(node);
|
|
xmlFreeNode(node);
|
|
}
|
|
else
|
|
{
|
|
delete_unused_whitespace_r(node);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
delete_unused_whitespace(xmlDocPtr doc)
|
|
{
|
|
delete_unused_whitespace_r(xmlDocGetRootElement(doc));
|
|
}
|
|
|
|
void publish_hits(char *out_filename)
|
|
{
|
|
char filename[255];
|
|
xmlChar *data;
|
|
xmlDocPtr doc = NULL, doc_myids = NULL;
|
|
xmlNodePtr root_node, node, hi, child;
|
|
xmlAttrPtr attr;
|
|
int out_filename_exists = 0;
|
|
|
|
sprintf(filename, "%s/%s", SYSCONFDIR, HIP_MYID_FILENAME);
|
|
doc_myids = xmlParseFile(filename);
|
|
if (doc_myids == NULL)
|
|
{
|
|
fprintf(stderr, "Error parsing xml file (%s)\n", filename);
|
|
return;
|
|
}
|
|
|
|
printf("Saving HITs to '%s'...\n", out_filename);
|
|
/*
|
|
* The below check for file existence will remove the
|
|
* "I/O warning : failed to load external entity ..." messages
|
|
*/
|
|
if (!access(out_filename, F_OK))
|
|
{
|
|
out_filename_exists = 1;
|
|
doc = xmlParseFile(out_filename);
|
|
}
|
|
/* append to existing file */
|
|
if (out_filename_exists && doc)
|
|
{
|
|
printf("Note: the file %s already exists, your ", out_filename);
|
|
printf("HITs will be appended to the end.\n");
|
|
delete_unused_whitespace(doc);
|
|
root_node = xmlDocGetRootElement(doc);
|
|
xmlDocSetRootElement(doc, root_node);
|
|
/* create a new file */
|
|
}
|
|
else
|
|
{
|
|
doc = xmlNewDoc(BAD_CAST "1.0");
|
|
node = xmlNewComment(
|
|
BAD_CAST "The following HITs can be "
|
|
"copied into a " HIP_KNOWNID_FILENAME
|
|
" file.");
|
|
xmlDocSetRootElement(doc, node);
|
|
root_node = xmlNewNode(NULL, BAD_CAST "known_host_identities");
|
|
xmlAddSibling(node, root_node);
|
|
}
|
|
|
|
node = xmlDocGetRootElement(doc_myids);
|
|
for (node = node->children; node; node = node->next)
|
|
{
|
|
if (strcmp((char *)node->name, "host_identity") != 0)
|
|
{
|
|
continue;
|
|
}
|
|
hi = xmlNewChild(root_node,NULL,BAD_CAST "host_identity", NULL);
|
|
/* copy attributes */
|
|
for (attr = node->properties; attr; attr = attr->next)
|
|
{
|
|
if ((attr->type == XML_ATTRIBUTE_NODE) &&
|
|
(attr->children) &&
|
|
(attr->children->type == XML_TEXT_NODE))
|
|
{
|
|
data = attr->children->content;
|
|
}
|
|
else /* no attribute value */
|
|
{
|
|
continue;
|
|
}
|
|
/* save recognized attributes */
|
|
if ((strcmp((char *)attr->name, "alg") == 0) ||
|
|
(strcmp((char *)attr->name, "alg_id") == 0) ||
|
|
(strcmp((char *)attr->name, "anon") == 0) ||
|
|
(strcmp((char *)attr->name, "incoming") == 0) ||
|
|
(strcmp((char *)attr->name, "length") == 0))
|
|
{
|
|
xmlNewProp(hi, BAD_CAST attr->name,
|
|
BAD_CAST data);
|
|
}
|
|
}
|
|
/* copy the children nodes that we wish to publish */
|
|
for (child = node->children; child; child = child->next)
|
|
{
|
|
if (strcmp((char *)child->name, "text") == 0)
|
|
{
|
|
continue;
|
|
}
|
|
if ((strcmp((char *)child->name, "name") != 0) &&
|
|
(strcmp((char *)child->name, "HIT") != 0) &&
|
|
(strcmp((char *)child->name, "LSI") != 0) &&
|
|
(strcmp((char *)child->name, "addr") != 0))
|
|
{
|
|
continue;
|
|
}
|
|
data = xmlNodeGetContent(child);
|
|
xmlNewChild(hi, NULL, BAD_CAST child->name,
|
|
BAD_CAST data);
|
|
xmlFree(data);
|
|
}
|
|
}
|
|
|
|
xmlSaveFormatFileEnc(out_filename, doc, "UTF-8", 1);
|
|
xmlFreeDoc(doc);
|
|
|
|
}
|
|
|
|
void generate_conf_file(char *filename)
|
|
{
|
|
xmlDocPtr doc = NULL;
|
|
xmlNodePtr root_node, node;
|
|
doc = xmlNewDoc(BAD_CAST "1.0");
|
|
|
|
printf("Saving default configuration to '%s'...\n", filename);
|
|
|
|
root_node = xmlNewNode(NULL, BAD_CAST "hip_configuration");
|
|
xmlDocSetRootElement(doc, root_node);
|
|
xmlNewDocComment(doc, BAD_CAST "HIP Configuration File");
|
|
|
|
xmlNewChild(root_node, NULL, BAD_CAST "cookie_difficulty",BAD_CAST "10");
|
|
xmlNewChild(root_node, NULL, BAD_CAST "packet_timeout", BAD_CAST "10");
|
|
xmlNewChild(root_node, NULL, BAD_CAST "max_retries", BAD_CAST "5");
|
|
xmlNewChild(root_node, NULL, BAD_CAST "sa_lifetime", BAD_CAST "900");
|
|
xmlNewChild(root_node, NULL, BAD_CAST "send_hi_name", BAD_CAST "yes");
|
|
xmlNewChild(root_node, NULL, BAD_CAST "dh_group", BAD_CAST "3");
|
|
xmlNewChild(root_node, NULL, BAD_CAST "dh_lifetime", BAD_CAST "900");
|
|
xmlNewChild(root_node, NULL, BAD_CAST "r1_lifetime", BAD_CAST "300");
|
|
xmlNewChild(root_node, NULL, BAD_CAST "failure_timeout", BAD_CAST "50");
|
|
xmlNewChild(root_node, NULL, BAD_CAST "msl", BAD_CAST "5");
|
|
xmlNewChild(root_node, NULL, BAD_CAST "ual", BAD_CAST "600");
|
|
xmlNewChild(root_node, NULL, BAD_CAST "min_reg_lifetime",BAD_CAST "96");
|
|
xmlNewChild(root_node, NULL,BAD_CAST "max_reg_lifetime",BAD_CAST "255");
|
|
node = xmlNewChild(root_node, NULL, BAD_CAST "hip_sa", NULL);
|
|
node = xmlNewChild(node, NULL, BAD_CAST "transforms", NULL);
|
|
xmlNewChild(node, NULL, BAD_CAST "id", BAD_CAST "1");
|
|
xmlNewChild(node, NULL, BAD_CAST "id", BAD_CAST "2");
|
|
xmlNewChild(node, NULL, BAD_CAST "id", BAD_CAST "3");
|
|
xmlNewChild(node, NULL, BAD_CAST "id", BAD_CAST "4");
|
|
xmlNewChild(node, NULL, BAD_CAST "id", BAD_CAST "5");
|
|
xmlNewChild(node, NULL, BAD_CAST "id", BAD_CAST "6");
|
|
node = xmlNewChild(root_node, NULL, BAD_CAST "esp_sa", NULL);
|
|
node = xmlNewChild(node, NULL, BAD_CAST "transforms", NULL);
|
|
xmlNewChild(node, NULL, BAD_CAST "id", BAD_CAST "1");
|
|
xmlNewChild(node, NULL, BAD_CAST "id", BAD_CAST "2");
|
|
xmlNewChild(node, NULL, BAD_CAST "id", BAD_CAST "3");
|
|
xmlNewChild(node, NULL, BAD_CAST "id", BAD_CAST "4");
|
|
xmlNewChild(node, NULL, BAD_CAST "id", BAD_CAST "5");
|
|
xmlNewChild(node, NULL, BAD_CAST "id", BAD_CAST "6");
|
|
xmlNewChild(root_node, NULL, BAD_CAST "disable_dns_lookups",
|
|
BAD_CAST "no");
|
|
xmlNewChild(root_node, NULL, BAD_CAST "save_known_identities",
|
|
BAD_CAST "no");
|
|
xmlNewChild(root_node, NULL, BAD_CAST "disable_notify", BAD_CAST "no");
|
|
#ifdef __UMH__
|
|
xmlNewChild(root_node, NULL, BAD_CAST "disable_dns_thread",
|
|
BAD_CAST "yes");
|
|
xmlNewChild(root_node, NULL, BAD_CAST "enable_broadcast",BAD_CAST "no");
|
|
#endif
|
|
xmlNewChild(root_node, NULL, BAD_CAST "disable_udp",
|
|
#ifdef __MACOSX__
|
|
BAD_CAST "yes");
|
|
#else
|
|
BAD_CAST "no");
|
|
#endif
|
|
xmlSaveFormatFileEnc(filename, doc, "UTF-8", 1);
|
|
xmlFreeDoc(doc);
|
|
}
|
|
|
|
void print_hitgen_usage()
|
|
{
|
|
int i;
|
|
printf("usage: hitgen ");
|
|
printf("\t[-v] ");
|
|
printf("[-name <string>] ");
|
|
printf("[-noinput] ");
|
|
printf("[-file <file>] ");
|
|
printf("[-append]\n");
|
|
printf("\t\t[-type DSA|RSA] ");
|
|
printf("[-bits|length <NN>] ");
|
|
printf("[-anon] ");
|
|
printf("[-incoming]\n");
|
|
printf("\t\t[-publish] ");
|
|
printf("[-conf]\n");
|
|
printf("Generate host identities (public/private key pairs) for use"
|
|
" with OpenHIP.\n");
|
|
printf("General options:\n");
|
|
printf(" -v \t\t show verbose debugging information\n");
|
|
printf(" -name <string>\t is the human-readable handle for the HI\n");
|
|
printf(" -noinput \t don't ask to seed random number generator\n");
|
|
printf(" -file <file> \t write output to the specified file\n");
|
|
printf(" -append\t append identity if file already exists\n");
|
|
printf("Host identitiy generation:\n");
|
|
printf(" -type \tfollowed by \"DSA\" or \"RSA\" specifies key type\n");
|
|
printf(" -bits \t\t specifies the length in bits for (P,G,Y)\n");
|
|
printf(" -length \t specifies the length in bytes for (P,G,Y)\n");
|
|
printf(" -anon \t\t sets the anonymous flag for this HI\n");
|
|
printf(" -incoming \t unsets the allow incoming flag for this HI\n");
|
|
printf("Other operating modes:\n");
|
|
printf(" -publish \t extract HITs from the existing '%s'\n",
|
|
HIP_MYID_FILENAME);
|
|
printf("\t\t file and create a file named ");
|
|
printf("'hostname_host_identities.pub.xml'\n");
|
|
printf(
|
|
" -conf \t\t generates a default '%s' file (overwrites existing)"
|
|
"\n",
|
|
HIP_CONF_FILENAME);
|
|
printf("Configuration files are stored in '%s'.\n", SYSCONFDIR);
|
|
printf("By default, identities are generated and written to '%s'\n",
|
|
HIP_MYID_FILENAME);
|
|
printf("with the string of 'default', the anonymous flag set to false");
|
|
printf(", allow \nincoming set to true, for each of the default ");
|
|
printf("lengths (");
|
|
for (i = 0; i < (sizeof(default_sizes) / sizeof(int)); i++)
|
|
{
|
|
printf("%d ", default_sizes[i]);
|
|
}
|
|
printf("bits).\n\n");
|
|
}
|
|
|
|
/*
|
|
* main()
|
|
*
|
|
* opens hip.conf file and calls generate_HI()
|
|
*
|
|
*/
|
|
int main(int argc, char *argv[])
|
|
{
|
|
char name[255], basename[255], filename[255];
|
|
char rnd_seed[255];
|
|
int i, have_filename = 0, do_publish = 0, do_conf = 0, do_noinput = 0;
|
|
int do_append = 0;
|
|
#ifdef HIP_VPLS
|
|
int do_sc_out = 0;
|
|
#endif
|
|
hi_options opts;
|
|
xmlDocPtr doc = NULL;
|
|
xmlNodePtr root_node = NULL;
|
|
int my_filename_exists = 0;
|
|
|
|
#ifndef __WIN32__
|
|
struct stat stbuf;
|
|
|
|
snprintf(filename, sizeof(filename), "%s", SYSCONFDIR);
|
|
if (stat(filename, &stbuf) < 0)
|
|
{
|
|
mkdir(filename, 755);
|
|
}
|
|
#else
|
|
WORD wVer = MAKEWORD( 2, 2);
|
|
WSADATA wsaData;
|
|
HMODULE hLib = LoadLibrary("ADVAPI32.DLL");
|
|
BOOLEAN (APIENTRY *pfn)(void*,
|
|
ULONG) =
|
|
(BOOLEAN (APIENTRY*)(void*,ULONG))GetProcAddress(
|
|
hLib,
|
|
"SystemFunction036");
|
|
|
|
WSAStartup(wVer, &wsaData);
|
|
#endif /* __WIN32__ */
|
|
|
|
/*
|
|
* Set default values
|
|
*/
|
|
if (gethostname(basename, 255) < 0)
|
|
{
|
|
sprintf(basename, "default");
|
|
}
|
|
sprintf(filename, "%s/%s", SYSCONFDIR, HIP_MYID_FILENAME);
|
|
OPT.debug = D_DEFAULT;
|
|
|
|
opts.type = 0;
|
|
opts.bitsize = 0;
|
|
opts.anon = 0;
|
|
opts.incoming = 1;
|
|
opts.r1count = 10;
|
|
opts.name = name;
|
|
|
|
/*
|
|
* Command-line parameters
|
|
*/
|
|
argv++, argc--;
|
|
while (argc > 0)
|
|
{
|
|
if (strcmp(*argv, "-v") == 0)
|
|
{
|
|
OPT.debug = D_VERBOSE;
|
|
argv++, argc--;
|
|
continue;
|
|
}
|
|
else if (strcmp(*argv, "-name") == 0)
|
|
{
|
|
argv++, argc--;
|
|
strncpy(basename, *argv, sizeof(basename));
|
|
argv++, argc--;
|
|
continue;
|
|
}
|
|
else if (strcmp(*argv, "-type") == 0)
|
|
{
|
|
argv++, argc--;
|
|
if (strcmp(*argv, "DSA") == 0)
|
|
{
|
|
opts.type = HI_ALG_DSA;
|
|
}
|
|
else if (strcmp(*argv, "RSA") == 0)
|
|
{
|
|
opts.type = HI_ALG_RSA;
|
|
}
|
|
else
|
|
{
|
|
printf("Invalid HI type.\n");
|
|
}
|
|
argv++, argc--;
|
|
continue;
|
|
}
|
|
else if (strcmp(*argv, "-bits") == 0)
|
|
{
|
|
argv++, argc--;
|
|
sscanf(*argv, "%d", &opts.bitsize);
|
|
argv++, argc--;
|
|
continue;
|
|
}
|
|
else if (strcmp(*argv, "-length") == 0)
|
|
{
|
|
int length;
|
|
argv++, argc--;
|
|
sscanf(*argv, "%d", &length);
|
|
opts.bitsize = length * 8;
|
|
argv++, argc--;
|
|
continue;
|
|
}
|
|
else if (strcmp(*argv, "-anon") == 0)
|
|
{
|
|
argv++, argc--;
|
|
opts.anon = 1;
|
|
continue;
|
|
}
|
|
else if (strcmp(*argv, "-incoming") == 0)
|
|
{
|
|
argv++, argc--;
|
|
opts.incoming = 0;
|
|
continue;
|
|
}
|
|
else if (strcmp(*argv, "-r1count") == 0)
|
|
{
|
|
argv++, argc--;
|
|
sscanf(*argv, "%llu", &opts.r1count);
|
|
argv++, argc--;
|
|
continue;
|
|
}
|
|
else if (strcmp(*argv, "-file") == 0)
|
|
{
|
|
argv++, argc--;
|
|
sprintf(filename, "%s", *argv);
|
|
have_filename = 1;
|
|
argv++, argc--;
|
|
continue;
|
|
}
|
|
else if (strcmp(*argv, "-publish") == 0)
|
|
{
|
|
do_publish = 1;
|
|
argv++, argc--;
|
|
continue;
|
|
}
|
|
else if (strcmp(*argv, "-conf") == 0)
|
|
{
|
|
do_conf = 1;
|
|
argv++, argc--;
|
|
continue;
|
|
}
|
|
else if (strcmp(*argv, "-noinput") == 0)
|
|
{
|
|
do_noinput = 1;
|
|
argv++, argc--;
|
|
continue;
|
|
}
|
|
else if (strcmp(*argv, "-append") == 0)
|
|
{
|
|
do_append = 1;
|
|
argv++, argc--;
|
|
continue;
|
|
#ifdef HIP_VPLS
|
|
}
|
|
else if (strcmp(*argv, "-scout") == 0)
|
|
{
|
|
do_sc_out = 1;
|
|
argv++, argc--;
|
|
continue;
|
|
#endif
|
|
}
|
|
print_hitgen_usage();
|
|
exit(1);
|
|
|
|
}
|
|
|
|
/* Non-interactive modes */
|
|
if (do_publish)
|
|
{
|
|
if (!have_filename)
|
|
{
|
|
sprintf(filename, "%s%s%s", HIP_PUB_PREFIX, basename,
|
|
HIP_PUB_SUFFIX);
|
|
}
|
|
publish_hits(filename);
|
|
exit(0);
|
|
}
|
|
else if (do_conf)
|
|
{
|
|
if (!have_filename)
|
|
{
|
|
sprintf(filename, "%s", HIP_CONF_FILENAME);
|
|
}
|
|
generate_conf_file(filename);
|
|
exit(0);
|
|
}
|
|
|
|
/* Interactive mode */
|
|
printf("\nhitgen v%s\n\n", HIP_VERSION);
|
|
printf("This utility will generate host identities for this machine."
|
|
"\n\n");
|
|
/*
|
|
* The below check for file existence will remove the
|
|
* "I/O warning : failed to load external entity ..." messages
|
|
*/
|
|
if (!access(filename, F_OK))
|
|
{
|
|
if (!do_append)
|
|
{
|
|
printf("The file %s already exists. Use the -append "
|
|
"option to add identities to it.\n", filename);
|
|
exit(0);
|
|
}
|
|
my_filename_exists = 1;
|
|
doc = xmlParseFile(filename);
|
|
}
|
|
/* append to existing file */
|
|
if (my_filename_exists && doc)
|
|
{
|
|
printf("The file %s already exists, will append.\n",
|
|
filename);
|
|
delete_unused_whitespace(doc);
|
|
root_node = xmlDocGetRootElement(doc);
|
|
xmlDocSetRootElement(doc, root_node);
|
|
/* create a new file */
|
|
}
|
|
else
|
|
{
|
|
printf("The file %s does not exist; creating new file...\n",
|
|
filename);
|
|
doc = xmlNewDoc(BAD_CAST "1.0");
|
|
root_node = xmlNewNode(NULL, BAD_CAST "my_host_identities");
|
|
xmlDocSetRootElement(doc, root_node);
|
|
}
|
|
|
|
/* DTD support */
|
|
/* dtd = xmlCreateIntSubset(doc,BAD_CAST "root",NULL,BAD_CAST "x.dtd");
|
|
*/
|
|
/* xmlNewChild(parent, NsPtr ns, name, content) */
|
|
/* */
|
|
#ifdef HIP_VPLS
|
|
if (!do_sc_out)
|
|
{
|
|
#endif
|
|
if (do_noinput)
|
|
{
|
|
#ifdef __WIN32__
|
|
if (hLib)
|
|
{
|
|
printf("\nUsing SystemFunction036 to seed the random "
|
|
"number generator.\n");
|
|
pfn(rnd_seed, sizeof rnd_seed);
|
|
}
|
|
else
|
|
{
|
|
printf("\nUsing screen data to seed the random number "
|
|
"generator.\n");
|
|
/* versions of Windows wihout SystemFunction036 */
|
|
RAND_screen();
|
|
}
|
|
#else
|
|
FILE *f = fopen("/dev/urandom", "r");
|
|
if (f)
|
|
{
|
|
printf(
|
|
"\nUsing /dev/urandom to seed the random number "
|
|
"generator.\n");
|
|
if (fread(rnd_seed, sizeof(rnd_seed), 1, f) != 1)
|
|
{
|
|
printf("Warning: error reading /dev/urandom\n");
|
|
}
|
|
fclose(f);
|
|
}
|
|
else
|
|
{
|
|
printf(
|
|
"\nUsing the system clock to seed the random num"
|
|
"ber generator.\n");
|
|
gettimeofday((struct timeval*)rnd_seed, NULL);
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
printf("\nTo seed the random number generator, ");
|
|
printf("please type some random text:\n");
|
|
if (scanf("%s", rnd_seed) < 1)
|
|
{
|
|
printf("Warning: could not read any input.\n");
|
|
}
|
|
}
|
|
RAND_seed(rnd_seed, sizeof rnd_seed);
|
|
#ifdef HIP_VPLS
|
|
}
|
|
|
|
#endif
|
|
|
|
if (opts.bitsize)
|
|
{
|
|
/* generate only one HI for the specified length */
|
|
if (!opts.type)
|
|
{
|
|
opts.type = HI_ALG_DSA;
|
|
}
|
|
sprintf(opts.name, "%s-%d", basename, opts.bitsize);
|
|
#ifdef HIP_VPLS
|
|
if (do_sc_out)
|
|
{
|
|
output_HI(root_node, &opts);
|
|
}
|
|
else
|
|
#endif
|
|
generate_HI(root_node, &opts);
|
|
}
|
|
else
|
|
{
|
|
/* generate a HI for each of the default lengths */
|
|
for (i = 0; i < (sizeof(default_sizes) / sizeof(int)); i++)
|
|
{
|
|
if (!opts.type)
|
|
{
|
|
opts.type = HI_ALG_RSA;
|
|
}
|
|
opts.bitsize = default_sizes[i];
|
|
sprintf(opts.name, "%s-%d", basename, opts.bitsize);
|
|
#ifdef HIP_VPLS
|
|
if (do_sc_out)
|
|
{
|
|
output_HI(root_node, &opts);
|
|
}
|
|
else
|
|
#endif
|
|
generate_HI(root_node, &opts);
|
|
}
|
|
}
|
|
|
|
printf("\nStoring results to file '%s'.\n\n", filename);
|
|
xmlSaveFormatFileEnc(filename, doc, "UTF-8", 1);
|
|
xmlFreeDoc(doc);
|
|
|
|
#ifndef __WIN32__
|
|
/* Change permissions of my_host_identities to 600 */
|
|
if (chmod(filename, S_IRUSR | S_IWUSR) < 0)
|
|
{
|
|
printf("Error setting permissions for '%s'\n", filename);
|
|
}
|
|
#else
|
|
WSACleanup();
|
|
#endif
|
|
return(0);
|
|
}
|
|
|