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
462 lines
18 KiB
4 years ago
|
/***************************************************************************/
|
||
|
/* */
|
||
|
/* 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);
|
||
|
}
|
||
|
|
||
|
|