home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
crypl200.zip
/
LIB_CERT.C
< prev
next >
Wrap
Text File
|
1996-10-07
|
13KB
|
447 lines
/****************************************************************************
* *
* cryptlib Certificate Management Routines *
* Copyright Peter Gutmann 1995-1996 *
* *
****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "crypt.h"
#ifdef INC_ALL
#include "asn1keys.h"
#else
#include "keymgmt/asn1keys.h"
#endif /* Compiler-specific includes */
/* The structure which holds information on a list element */
typedef struct LI {
/* The list element payload */
void *data;
int dataSize;
/* The next and previous list element in the linked list of elements */
struct LI *next, *prev;
} LISTITEM;
/* The structure which stores information on a certificate */
typedef struct RI {
/* The DER-encoded SubjectPublicKeyInfo */
void *keyInfo; /* Key information */
int keyInfoSize; /* Size of the key information */
/* General certificate information */
long serialNumber; /* This may be a bignum, but there don't
seem to be any implementations which
do this */
time_t validityNotBefore; /* Validity start */
time_t validityNotAfter; /* Validity end */
/* Name fields */
LISTITEM *issuerNameHead, *issuerNameTail; /* Issuer name */
LISTITEM *subjectNameHead, *subjectNameTail;/* Subject name */
/* A check value so we can determine whether the keyset context has been
initialised or not. This is needed because passing in an
uninitialised block of memory as a keyset context can lead to problems
when we try to dereference wild pointers */
LONG checkValue;
/* The next and previous certificate context in the linked list of
contexts */
struct RI *next, *prev;
} CERT_INFO;
/* Macros to convert to/from certificate contexts. These are analogous to
the encryption context macros in crypt.h */
#define CERT_TO_INFO( x ) ( CERT_INFO * ) ( ( BYTE * ) x - cryptContextConversionOffset )
#define INFO_TO_CERT( x ) ( CRYPT_CERT ) ( ( BYTE * ) x + cryptContextConversionOffset )
/****************************************************************************
* *
* List Functions for Certificate Information *
* *
****************************************************************************/
/* Insert an element into a list */
static int insertElement( LISTITEM **listHead, LISTITEM **listTail,
void *data, int dataLength )
{
LISTITEM *newElement;
/* Allocate memory for the new element */
if( ( newElement = ( LISTITEM * ) malloc( sizeof( LISTITEM ) ) ) == NULL )
return( CRYPT_NOMEM );
if( ( newElement->data = malloc( dataLength ) ) == NULL )
{
free( newElement );
return( CRYPT_NOMEM );
}
memset( newElement, 0, sizeof( LISTITEM ) );
memcpy( newElement->data, data, dataLength );
newElement->dataSize = dataLength;
/* Link it into the list */
if( *listHead == NULL )
*listHead = newElement;
else
{
( *listTail )->next = newElement;
newElement->prev = *listTail;
}
*listTail = newElement;
return( CRYPT_OK );
}
/* Delete an element from a list */
static void deleteElement( LISTITEM **listHead, LISTITEM **listTail,
LISTITEM *listItem )
{
LISTITEM *listPrevPtr = listItem->prev, *listNextPtr = listItem->next;
/* Remove the item from the list */
if( listItem == *listHead )
{
/* Special case for first item */
*listHead = listNextPtr;
if( listNextPtr != NULL )
listNextPtr->prev = NULL;
}
else
{
/* Delete from the middle or the end of the chain */
listPrevPtr->next = listNextPtr;
if( listNextPtr != NULL )
listNextPtr->prev = listPrevPtr;
}
/* If this was the last element, move the tail pointer back */
if( *listTail == listItem )
*listTail = listPrevPtr;
/* Clear all data in the list item and free the memory */
zeroise( listItem->data, listItem->dataSize );
free( listItem->data );
zeroise( listItem, sizeof( LISTITEM ) );
free( listItem );
}
/* Delete a list */
static void deleteList( LISTITEM **listHead, LISTITEM **listTail )
{
LISTITEM *listPtr = *listHead;
/* Mark the list as being empty */
*listHead = *listTail = NULL;
/* If the list was empty, return now */
if( listPtr == NULL )
return;
/* Destroy any remaining list items */
while( listPtr != NULL )
{
LISTITEM *itemToFree = listPtr;
listPtr = listPtr->next;
zeroise( itemToFree->data, itemToFree->dataSize );
free( itemToFree->data );
zeroise( itemToFree, sizeof( LISTITEM ) );
free( itemToFree );
}
}
/****************************************************************************
* *
* Memory Management Functions for Certificate Contexts *
* *
****************************************************************************/
/* The linked list of certificate contexts */
static CERT_INFO *certInfoListHead = NULL, *certInfoListTail;
/* Create a cert context and add it to the list */
static int createCertificateContext( CERT_INFO **certInfo )
{
CERT_INFO *newElement;
/* Allocate memory for the new cert context */
if( ( newElement = malloc( sizeof( CERT_INFO ) ) ) == NULL )
return( CRYPT_NOMEM );
memset( newElement, 0, sizeof( CERT_INFO ) );
/* Link it into the list */
if( certInfoListHead == NULL )
certInfoListHead = newElement;
else
{
certInfoListTail->next = newElement;
newElement->prev = certInfoListTail;
}
certInfoListTail = newElement;
*certInfo = newElement;
return( CRYPT_OK );
}
/* Delete a certificate context from the list */
static void deleteCertificateContext( CERT_INFO *certInfo )
{
CERT_INFO *certInfoPrevPtr = certInfo->prev, *certInfoNextPtr = certInfo->next;
/* Remove the cert context from the list of contexts */
if( certInfo == certInfoListHead )
{
/* Special case for first certificate */
certInfoListHead = certInfoNextPtr;
if( certInfoNextPtr != NULL )
certInfoNextPtr->prev = NULL;
}
else
{
/* Delete from the middle or the end of the chain */
certInfoPrevPtr->next = certInfoNextPtr;
if( certInfoNextPtr != NULL )
certInfoNextPtr->prev = certInfoPrevPtr;
}
/* If this was the last element, move the tail pointer back */
if( certInfoListTail == certInfo )
certInfoListTail = certInfoPrevPtr;
/* Clear all data in the cert context and free the memory */
zeroise( certInfo, sizeof( CERT_INFO ) );
free( certInfo );
}
/* Delete all certificate contexts */
int deleteAllCertificateContexts( void )
{
CERT_INFO *certInfoListPtr = certInfoListHead;
/* Mark the list as being empty */
certInfoListHead = certInfoListTail = NULL;
/* If there are no remaining allocated cert contexts, return now */
if( certInfoListPtr == NULL )
return( CRYPT_OK );
/* Destroy any remaining cert contexts */
while( certInfoListPtr != NULL )
{
CERT_INFO *certInfoToFree = certInfoListPtr;
certInfoListPtr = certInfoListPtr->next;
cryptDestroyCert( INFO_TO_CERT( certInfoToFree ) );
}
/* If there were cert contexts still allocated, warn the user about
them */
return( CRYPT_ORPHAN );
}
/****************************************************************************
* *
* Certificate Management API Functions *
* *
****************************************************************************/
/* Create/destroy a certificate */
CRET cryptCreateCert( CRYPT_CERT CPTR certificate,
const CRYPT_CONTEXT pkcContext )
{
STREAM stream;
CERT_INFO *certInfoPtr;
CRYPT_INFO *pkcInfoPtr = CONTEXT_TO_INFO( pkcContext );
void *keyInfo;
int keyInfoSize, status;
/* Perform basic error checking */
if( certificate == NULL )
return( CRYPT_BADPARM1 );
if( isBadCookie( pkcContext ) || \
pkcInfoPtr->checkValue != CRYPT_MAGIC || \
!pkcInfoPtr->keySet || !pkcInfoPtr->isPKCcontext )
return( CRYPT_BADPARM2 );
/* Find out how large the encoded key information will be and allocate
memory for it */
sMemNullOpen( &stream );
status = writePublicKey( &stream, pkcInfoPtr->pkcInfo );
keyInfoSize = sMemSize( &stream );
sMemClose( &stream );
if( cryptStatusError( status ) )
return( status );
if( ( keyInfo = malloc( keyInfoSize ) ) == NULL )
return( CRYPT_NOMEM );
/* Create the certificate context */
if( ( status = createCertificateContext( &certInfoPtr ) ) != CRYPT_OK )
{
free( keyInfo );
return( status );
}
/* Encode the PKC information as a SubjectPublicKey and store the result
in the public-key field of the certificate. We don't need to check
the status of writePublicKey() this time since we just called it a few
lines ago */
sMemOpen( &stream, keyInfo, keyInfoSize );
writePublicKey( &stream, pkcInfoPtr->pkcInfo );
sMemDisconnect( &stream );
certInfoPtr->keyInfo = keyInfo;
certInfoPtr->keyInfoSize = keyInfoSize;
/* Set the check value */
certInfoPtr->checkValue = CRYPT_MAGIC;
/* Convert the keyset information pointer to a certificate context and
return it to the user */
*certificate = INFO_TO_CERT( certInfoPtr );
return( CRYPT_OK );
}
CRET cryptDestroyCert( CRYPT_CERT certificate )
{
CERT_INFO *certInfoPtr = CERT_TO_INFO( certificate );
/* Perform basic error checking */
if( isBadCookie( certificate ) )
return( CRYPT_BADPARM1 );
if( certInfoPtr->checkValue != CRYPT_MAGIC )
return( CRYPT_NOTINITED );
/* Clear the SubjectPublicKeyInfo if necessary */
if( certInfoPtr->keyInfo != NULL )
{
zeroise( certInfoPtr->keyInfo, certInfoPtr->keyInfoSize );
free( certInfoPtr->keyInfo );
}
/* Clear the name fields if necessary */
if( certInfoPtr->issuerNameHead != NULL )
deleteList( &certInfoPtr->issuerNameHead, &certInfoPtr->issuerNameTail );
if( certInfoPtr->subjectNameHead != NULL )
deleteList( &certInfoPtr->subjectNameHead, &certInfoPtr->subjectNameTail );
/* Delete the certificate itself */
deleteCertificateContext( certInfoPtr );
return( CRYPT_OK );
}
#if 0
/* Get/add/delete certificate components */
CRET cryptGetCertComponent( CRYPT_CERT certificate,
const CRYPT_CERTINFO_TYPE certInfoType,
void CPTR certInfo );
CRET cryptAddCertComponent( CRYPT_CERT certificate,
const CRYPT_CERTINFO_TYPE certInfoType,
const void CPTR certInfo );
CRET cryptDeleteCertComponent( CRYPT_CERT certificate,
const CRYPT_CERTINFO_TYPE certInfoType,
const void CPTR certInfo );
/* Sign a certificate */
CRET cryptSignCert( CRYPT_CERT certificate, CRYPT_CONTEXT pkcContext );
#endif /* 0 */
/* Import a certificate */
CRET cryptImportCert( const void CPTR certObject, CRYPT_CERT CPTR certificate )
{
CERT_INFO *certInfoPtr = CERT_TO_INFO( certificate );
BYTE *objectPtr = ( BYTE * ) certObject;
void *keyInfo;
int keyInfoSize, status;
/* Perform basic error checking */
if( certObject == NULL )
return( CRYPT_BADPARM1 );
if( isBadCookie( certificate ) || \
certInfoPtr->checkValue != CRYPT_MAGIC )
return( CRYPT_BADPARM2 );
/* In this release all that's supported is reading the raw
SubjectPublicKeyInfo record from the input */
if( memcmp( objectPtr, "RAW0", 4 ) )
return( CRYPT_BADDATA );
objectPtr += 4;
/* Find out how big the object is */
keyInfoSize = *objectPtr++ << 8;
keyInfoSize += *objectPtr++;
/* Allocate room for the SubjectPublicKeyInfo record */
if( ( keyInfo = malloc( keyInfoSize ) ) == NULL )
return( CRYPT_NOMEM );
/* Create the certificate context */
if( ( status = createCertificateContext( &certInfoPtr ) ) != CRYPT_OK )
{
free( keyInfo );
return( status );
}
memcpy( keyInfo, objectPtr, keyInfoSize );
certInfoPtr->keyInfo = keyInfo;
/* Set the check value and convert the keyset information pointer to a
certificate context */
certInfoPtr->checkValue = CRYPT_MAGIC;
*certificate = INFO_TO_CERT( certInfoPtr );
return( CRYPT_OK );
}
/* Export a certificate */
CRET cryptExportCert( void CPTR certObject, int CPTR certObjectLength,
CRYPT_CERT certificate )
{
CERT_INFO *certInfoPtr = CERT_TO_INFO( certificate );
/* Perform basic error checking */
if( certObject == NULL )
return( CRYPT_BADPARM1 );
if( certObjectLength == NULL )
return( CRYPT_BADPARM2 );
if( isBadCookie( certificate ) || \
certInfoPtr->checkValue != CRYPT_MAGIC )
return( CRYPT_BADPARM3 );
/* In this release all that's supported is writing the raw
SubjectPublicKeyInfo record to the output */
*certObjectLength = certInfoPtr->keyInfoSize + 6;
if( certObject != NULL )
{
BYTE *objectPtr = certObject;
memcpy( objectPtr, "RAW0", 4 );
objectPtr += 4;
*objectPtr++ = certInfoPtr->keyInfoSize >> 8;
*objectPtr++ = certInfoPtr->keyInfoSize & 0xFF;
memcpy( objectPtr, certInfoPtr->keyInfo, certInfoPtr->keyInfoSize + 2 );
}
return( CRYPT_OK );
}