You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

462 lines
18 KiB

/***************************************************************************/
/* */
/* Project: OpenSLP - OpenSource implementation of Service Location */
/* Protocol Version 2 */
/* */
/* File: slp_spi.h */
/* */
/* Abstract: Functions for fetching SPI information from the filesystem */
/* Current implementation uses OpenSSL. For details see */
/* (see http://www.openssl.org */
/* */
/*-------------------------------------------------------------------------*/
/* */
/* Please submit patches to http://www.openslp.org */
/* */
/*-------------------------------------------------------------------------*/
/* */
/* Copyright (C) 2000 Caldera Systems, Inc */
/* All rights reserved. */
/* */
/* Redistribution and use in source and binary forms, with or without */
/* modification, are permitted provided that the following conditions are */
/* met: */
/* */
/* Redistributions of source code must retain the above copyright */
/* notice, this list of conditions and the following disclaimer. */
/* */
/* Redistributions in binary form must reproduce the above copyright */
/* notice, this list of conditions and the following disclaimer in */
/* the documentation and/or other materials provided with the */
/* distribution. */
/* */
/* Neither the name of Caldera Systems nor the names of its */
/* contributors may be used to endorse or promote products derived */
/* from this software without specific prior written permission. */
/* */
/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */
/* `AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */
/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */
/* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE CALDERA */
/* SYSTEMS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */
/* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON */
/* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */
/* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
/* */
/***************************************************************************/
#include "slp_spi.h"
#include "slp_xmalloc.h"
#include <string.h>
#include <stdio.h>
#include <openssl/pem.h>
#include <openssl/bn.h>
#define MAX_SPI_ENTRY_LEN 1024
#define PUBLIC_TOKEN "PUBLIC"
#define PRIVATE_TOKEN "PRIVATE"
/*-------------------------------------------------------------------------*/
void SLPSpiEntryFree(SLPSpiEntry* victim)
/*-------------------------------------------------------------------------*/
{
if(victim->keyfilename) xfree(victim->keyfilename);
if(victim->spistr) xfree(victim->spistr);
if(victim->key) SLPCryptoDSAKeyDestroy(victim->key);
if(victim) xfree(victim);
}
/*-------------------------------------------------------------------------*/
SLPSpiEntry* SLPSpiEntryFind(SLPList* cache,
int keytype,
int spistrlen,
const char* spistr)
/* pass in null spistr to find the first Cached entry */
/*-------------------------------------------------------------------------*/
{
SLPSpiEntry* entry = (SLPSpiEntry*)cache->head;
while(entry)
{
if(spistr)
{
if (entry->spistrlen == spistrlen &&
memcmp(entry->spistr,spistr,spistrlen) == 0 &&
entry->keytype == keytype)
{
return entry;
}
}
else
{
if(keytype == SLPSPI_KEY_TYPE_ANY || entry->keytype == keytype)
{
return entry;
}
}
entry = (SLPSpiEntry*)entry->listitem.next;
}
return 0;
}
/*-------------------------------------------------------------------------*/
SLPCryptoDSAKey* SLPSpiReadKeyFile(const char* keyfile, int keytype)
/*-------------------------------------------------------------------------*/
{
FILE* fp;
SLPCryptoDSAKey* result = 0;
fp = fopen(keyfile,"r");
if(fp)
{
if(keytype == SLPSPI_KEY_TYPE_PUBLIC)
{
result = PEM_read_DSA_PUBKEY(fp, &result, NULL, NULL);
}
else if (keytype == SLPSPI_KEY_TYPE_PRIVATE)
{
result = PEM_read_DSAPrivateKey(fp, &result, NULL, NULL);
}
fclose(fp);
}
return result;
}
/*-------------------------------------------------------------------------*/
SLPSpiEntry* SLPSpiReadSpiFile(FILE* fp, int keytype)
/* Caller needs to free returned memory SLPSpiEntryFree() */
/*-------------------------------------------------------------------------*/
{
SLPSpiEntry* result;
char tmp;
char* line;
char* slider1;
char* slider2;
/*----------------------------*/
/* Allocate memory for result */
/*----------------------------*/
line = (char*) xmalloc(MAX_SPI_ENTRY_LEN);
result = (SLPSpiEntry*) xmalloc(sizeof(SLPSpiEntry));
if(result == 0 || line == 0)
{
return 0;
}
memset(result,0,sizeof(SLPSpiEntry));
/*---------------------------*/
/* Read the next valid entry */
/*---------------------------*/
while(fgets(line, MAX_SPI_ENTRY_LEN, fp))
{
/*----------------------*/
/* read the first token */
/*----------------------*/
slider1 = line;
/* skip leading whitespace */
while(*slider1 && *slider1 <= 0x20) slider1++;
/* skip all white lines */
if(*slider1 == 0) continue;
/* skip commented lines */
if(*slider1 == '#') continue;
/* PUBLIC|PRIVATE */
slider2 = slider1;
while(*slider2 && *slider2 > 0x20) slider2++;
if(strncasecmp(PUBLIC_TOKEN,slider1,slider2-slider1) == 0)
{
if(keytype == SLPSPI_KEY_TYPE_PRIVATE) continue;
result->keytype = SLPSPI_KEY_TYPE_PUBLIC;
}
else if(strncasecmp(PRIVATE_TOKEN,slider1,slider2-slider1) == 0)
{
if(keytype == SLPSPI_KEY_TYPE_PUBLIC) continue;
result->keytype = SLPSPI_KEY_TYPE_PRIVATE;
}
else
{
/* unknown token */
continue;
}
/*-----------------------*/
/* read the second token */
/*-----------------------*/
slider1=slider2;
/* skip leading whitespace */
while(*slider1 && *slider1 <= 0x20) slider1++;
/* SPI string */
slider2 = slider1;
while(*slider2 && *slider2 > 0x20) slider2++;
/* SPI string is at slider1 length slider2 - slider1 */
result->spistr = (char*)xmalloc(slider2-slider1);
if(result->spistr)
{
memcpy(result->spistr,slider1,slider2-slider1);
result->spistrlen = slider2-slider1;
}
/*----------------------*/
/* read the third token */
/*----------------------*/
slider1=slider2;
/* skip leading whitespace */
while(*slider1 && *slider1 <= 0x20) slider1++;
/* SPI string */
slider2 = slider1;
while(*slider2 && *slider2 > 0x20) slider2++;
/* key file path is at slider1 length slider2 - slider1 */
tmp = *slider2;
*slider2 = 0;
result->keyfilename = xstrdup(slider1);
result->key = 0; /* read it later */
*slider2 = tmp;
/*-----------------*/
/* See what we got */
/*-----------------*/
if(result &&
result->spistr &&
result->keyfilename)
{
goto SUCCESS;
}
if(result->keyfilename) xfree(result->keyfilename);
if(result->spistr) xfree(result->spistr);
}
if (result)
{
xfree(result);
result = 0;
}
SUCCESS:
if (line) xfree(line);
return result;
}
/*=========================================================================*/
SLPSpiHandle SLPSpiOpen(const char* spifile, int cacheprivate)
/* Initializes SLP SPI data storage. */
/* */
/* Parameters: spifile (IN) path of slp.spi file */
/* cacheprivate (IN) should private keys be cached in handle */
/* */
/* Returns: valid pointer. NULL on failure */
/*=========================================================================*/
{
FILE* fp;
SLPSpiHandle result = 0;
SLPSpiEntry* spientry;
fp = fopen(spifile,"r");
if(fp)
{
result = xmalloc(sizeof(struct _SLPSpiHandle));
if(result == 0) return 0;
memset(result, 0, sizeof(struct _SLPSpiHandle));
result->spifile = xstrdup(spifile);
result->cacheprivate = cacheprivate;
while(1)
{
spientry = SLPSpiReadSpiFile(fp, SLPSPI_KEY_TYPE_ANY);
if(spientry == 0) break;
if(spientry->keytype == SLPSPI_KEY_TYPE_PRIVATE &&
cacheprivate == 0)
{
/* destroy the key cause we're not suppose to cache it */
SLPCryptoDSAKeyDestroy(spientry->key);
}
SLPListLinkHead(&(result->cache),(SLPListItem*)spientry);
}
fclose(fp);
}
return result;
}
/*=========================================================================*/
void SLPSpiClose(SLPSpiHandle hspi)
/* Release SLP SPI data storage associated with the specified SLPSpiHandle */
/* */
/* Parameters: hspi (IN) SLPSpiHandle to deinitialize */
/*=========================================================================*/
{
if(hspi)
{
if(hspi->spifile) xfree(hspi->spifile);
while(hspi->cache.count)
{
SLPSpiEntryFree((SLPSpiEntry*)SLPListUnlink(&(hspi->cache),hspi->cache.head));
}
xfree(hspi);
}
}
/*=========================================================================*/
char* SLPSpiGetDefaultSPI(SLPSpiHandle hspi,
int keytype,
int* spistrlen,
char** spistr)
/* Gets a reference to the default SPI string for the specified keytype */
/* */
/* Parameters: hspi (IN) handle obtained from call to SLPSpiOpen() */
/* keytype (IN) type of key */
/* spistrlen (OUT) length or the returned spistr */
/* spistr (OUT) pointer to spistr. MUST be freed by */
/* caller!! */
/* */
/* Returns: Pointer to the default SPI string. Pointer may *not* be NULL */
/* terminated */
/*=========================================================================*/
{
SLPSpiEntry* entry;
*spistr = 0;
*spistrlen = 0;
if(hspi)
{
entry = SLPSpiEntryFind(&(hspi->cache),keytype,0,0);
if(entry)
{
*spistr = xmalloc(entry->spistrlen);
if(*spistr)
{
memcpy(*spistr, entry->spistr, entry->spistrlen);
*spistrlen = entry->spistrlen;
}
}
}
return *spistr;
}
/*=========================================================================*/
SLPCryptoDSAKey* SLPSpiGetDSAKey(SLPSpiHandle hspi,
int keytype,
int spistrlen,
const char* spistr,
SLPCryptoDSAKey **key)
/* Fetches a copy of the private key file used to sign SLP messages. */
/* */
/* Parameters: hspi (IN) handle obtained from call to SLPSpiOpen() */
/* keytype (IN) the type of key desired */
/* spistrlen (IN) the length of the spistr */
/* spistr (IN) spistr associated with the key */
/* key (OUT) the private key. Caller should use */
/* SLPCryptoDSAKeyDestroy() to free key memory */
/* */
/* Returns: A valid pointer. NULL on failure. Caller should use */
/* SLPCryptoDSAKeyDestroy() to free key memory */
/*=========================================================================*/
{
SLPSpiEntry* tmp = 0;
/* For safety NULL out the key from the beginning */
*key = 0;
if(hspi)
{
tmp = SLPSpiEntryFind(&(hspi->cache),
keytype,
spistrlen,
spistr);
if(tmp)
{
if(tmp->key == 0)
{
if(keytype == SLPSPI_KEY_TYPE_PRIVATE && hspi->cacheprivate == 0)
{
*key = SLPSpiReadKeyFile(tmp->keyfilename,SLPSPI_KEY_TYPE_PRIVATE);
return *key;
}
tmp->key = SLPSpiReadKeyFile(tmp->keyfilename,keytype);
if (tmp->key == 0)
return 0;
}
*key = SLPCryptoDSAKeyDup(tmp->key);
}
}
return *key;
}
/*=========================================================================*/
int SLPSpiCanVerify(SLPSpiHandle hspi,
int spistrlen,
const char* spistr)
/* Determine if we understand the specified SPI. No SPI is always */
/* returns true */
/* */
/* Parameters: hspi (IN) handle obtained from call to SLPSpiOpen() */
/* spistrlen (IN) the length of the spistr */
/* spistr (IN) the SPI string */
/* */
/* Returns Non-zero if we verify specified the SPI */
/*=========================================================================*/
{
if (hspi == 0)
{
return 0;
}
if(spistrlen == 0 || spistr == NULL)
{
return 1;
}
return (SLPSpiEntryFind(&(hspi->cache),
SLPSPI_KEY_TYPE_PUBLIC,
spistrlen,
spistr) != 0);
}
/*=========================================================================*/
int SLPSpiCanSign(SLPSpiHandle hspi,
int spistrlen,
const char* spistr)
/* Determine if we understand the specified SPI. No SPI is always */
/* return true */
/* */
/* Parameters: hspi (IN) handle obtained from call to SLPSpiOpen() */
/* spistrlen (IN) the length of the spistr */
/* spistr (IN) the SPI string */
/* */
/* Returns Non-zero if we sign using the specified SPI */
/*=========================================================================*/
{
return (SLPSpiEntryFind(&(hspi->cache),
SLPSPI_KEY_TYPE_PRIVATE,
spistrlen,
spistr) != 0);
}