/**************************************************************************
*** COPYRIGHT (c) 2002 by TransNexus, Inc.                              ***
***                                                                     ***
*** This software is property of TransNexus, Inc.                       ***
*** This software is freely available under license from TransNexus.    ***
*** The license terms and conditions for free use of this software by   ***
*** third parties are defined in the OSP Toolkit Software License       ***
*** Agreement (LICENSE.txt).  Any use of this software by third         ***
*** parties, which does not comply with the terms and conditions of the ***
*** OSP Toolkit Software License Agreement is prohibited without        ***
*** the prior, express, written consent of TransNexus, Inc.             ***
***                                                                     ***
*** Thank you for using the OSP ToolKit(TM).  Please report any bugs,   ***
*** suggestions or feedback to support@transnexus.com                   ***
***                                                                     ***
**************************************************************************/







/*
 * osppkcs8.c - PKCS #8 Private Key Information Standard
 */


#include "osp/osp.h"
#include "osp/ospdatatypes.h"
#include "osp/ospasn1.h"
#include "osp/osppkcs8.h"
#include "osp/ospcrypto.h"

/* FUNCTION PROTOTYPES */

/* ---------------------------------------------------------*/
/* Member functions                                         */
/* ---------------------------------------------------------*/
/* ---------------------------------------------------------*/
/* Non-Member functions                                     */
/* ---------------------------------------------------------*/


/* This routine assumes the private key passed by the caller is an
RSAEncryption PKCS1 Private Key. It is converted to a OSPPASN1OBJECT and
wrapped to become a PKCS8 PrivateKeyInfo Encoded object */
int
OSPPPKCS8KeyInfoCreate(
    OSPTASN1OBJECT **ospvPrivateKeyInfo,
    OSPTPRIVATEKEY *ospvPrivateKey)
{   
    int errorcode = OSPC_ERR_NO_ERROR;

    OSPEASN1DATAREFID dataRefId = OSPEDRID_NOTDEFINED;
    OSPTASN1OBJECT  *privateKeyInfo = OSPC_OSNULL;
    OSPTASN1OBJECT *newObject = OSPC_OSNULL;
    OSPTASN1OBJECT *tmpObject = OSPC_OSNULL;

    unsigned char *rsaPrivateKey = OSPC_OSNULL;
    unsigned      rsaPrivateKeyLength = 0;

    int i = 0;

    if (ospvPrivateKey == OSPC_OSNULL)
    {
        errorcode = OSPC_ERR_PKCS8_INVALID_PRIVATE_KEY_POINTER;
        OSPM_DBGERRORLOG(errorcode, "Private Key is NULL");
    }

    if (errorcode == OSPC_ERR_NO_ERROR)
    {
        errorcode = OSPPASN1ObjectNew(&privateKeyInfo, OSPEDRID_PRIVATEKEYINFO);
    }

    /* The elements are a contentType OID, and a content element.  */
    /* Add the content type Element to the result list */
    for (i = 0 ;errorcode == OSPC_ERR_NO_ERROR ; i++)
    {
        switch(i)
        {
            case 0: /* Add VERSION Element */
            dataRefId = OSPEDRID_PVTKEYINF_VERSION;
            errorcode = OSPPASN1SmallIntegerEncode(&newObject, 
                OSPC_ASN1_PRIVATEKEYINFO_VERSION,
                dataRefId);
            break;

            case 1: /* Add PrivateKey Algorithm */
            dataRefId = OSPEDRID_PVTKEYINF_ALGORITHM;
            errorcode = OSPPASN1AlgorithmIdEncode(&tmpObject,
                OSPEID_RSAENCRYPTION, dataRefId);

            if (errorcode == OSPC_ERR_NO_ERROR)
            {
                errorcode = OSPPASN1ObjectCopy(&newObject, tmpObject);
            }

            OSPM_FREE(newObject->ElementInfo->Element); /* !!! PS */
            OSPM_FREE(newObject->ElementInfo); /* !!! PS */
            OSPPASN1ObjectDelete(&tmpObject);

            break;

            case 2: /* Add PrivateKey OctetString */
            dataRefId = OSPEDRID_PVTKEYINF_PRIVATEKEY;

            rsaPrivateKey = ospvPrivateKey->PrivateKeyData;
            rsaPrivateKeyLength = ospvPrivateKey->PrivateKeyLength;

            errorcode = OSPPASN1OctetStringEncode(&newObject,
                rsaPrivateKey, rsaPrivateKeyLength, 
                dataRefId);
            break;

            case 3: /* Add PrivateKey Attributes */
            dataRefId = OSPEDRID_PVTKEYINF_ATTRIBUTES;
            newObject = OSPC_OSNULL;/* None required for rsaPrivateKey */

            break;

            case 4:
            errorcode = OSPC_ERR_ASN1_PARSE_COMPLETE;
            break;

            default:
            errorcode = OSPC_ERR_PKCS7_ENCODING_ERROR;
            OSPM_DBGERRORLOG(errorcode, 
                "Unknown case encountered encoding PKCS7 SignerInfo");
        }

        if (errorcode == OSPC_ERR_NO_ERROR)
        {
            /* Add new object to this object */
            if (newObject != OSPC_OSNULL)
            {
                errorcode = OSPPASN1ObjectAddChild(privateKeyInfo, newObject,
                    dataRefId);
                OSPM_FREE(newObject); /* !!! PS */
                newObject = OSPC_OSNULL;
            }
        }
    }
    if (errorcode == OSPC_ERR_ASN1_PARSE_COMPLETE)
    {
        errorcode = OSPC_ERR_NO_ERROR;
    }

    if (errorcode == OSPC_ERR_NO_ERROR)
    {
        /* Complete the encoding for this object. Update results, elements, 
            etc. */
        errorcode = OSPPASN1ObjectDeparse(privateKeyInfo, 
            OSPEPTID_PRIVATEKEYINFO,
            OSPEDRID_PRIVATEKEYINFO);
    }

    if (errorcode == OSPC_ERR_NO_ERROR)
    {
        *ospvPrivateKeyInfo = privateKeyInfo;
    }
    else
    {
        /* Clean up from errors */
        OSPPASN1ObjectDelete(&privateKeyInfo);
    }

    return errorcode;
}


int
OSPPPKCS8KeyInfoTestContext(
    OSPTASN1OBJECT  *ospvPrivateKeyInfo)
{
    int errorcode = OSPC_ERR_NO_ERROR;

    if (ospvPrivateKeyInfo == OSPC_OSNULL)
    {
        errorcode = OSPC_ERR_PKCS8_INVALID_CONTEXT;
        OSPM_DBGERRORLOG(errorcode, 
            "PKCS#1 Private Key context is null pointer");
    }

    return errorcode;
}


void 
OSPPPKCS8KeyInfoDelete(
    OSPTASN1OBJECT  **ospvPrivateKeyInfo)
{
    OSPPASN1ObjectDelete(ospvPrivateKeyInfo);
}

int
OSPPKCS8KeyInfoGetEncodedKeyInfo(
    OSPTASN1OBJECT *ospvPrivateKeyInfo,
    unsigned char **ospvBERPrivateKeyInfo,
    unsigned      *ospvBERPrivateKeyInfoLength)
{
    int errorcode = OSPC_ERR_NO_ERROR;
    OSPTASN1ELEMENTINFO *eInfo = OSPC_OSNULL;

    errorcode = OSPPPKCS8KeyInfoTestContext(ospvPrivateKeyInfo);

    if ( errorcode == OSPC_ERR_NO_ERROR)
    {
        errorcode = OSPPPKCS8KeyInfoGetPrivateKeyElement(ospvPrivateKeyInfo, 
            OSPEDRID_PRIVATEKEYINFO, &eInfo);

    }
    if (errorcode == OSPC_ERR_NO_ERROR)
    {
        errorcode = OSPPASN1ElementGetElementData(eInfo, ospvBERPrivateKeyInfo,                                                 ospvBERPrivateKeyInfoLength);
    }

    return errorcode;
}

int
OSPPPKCS8KeyInfoGetPrivateKey(
    OSPTASN1OBJECT *ospvPrivateKeyInfo,
    unsigned char **ospvPrivateKey,
    unsigned      *ospvPrivateKeyLength)
{
    int errorcode = OSPC_ERR_NO_ERROR;
    OSPTASN1ELEMENTINFO *eInfo = OSPC_OSNULL;

    errorcode = OSPPPKCS8KeyInfoTestContext(ospvPrivateKeyInfo);

    if ( errorcode == OSPC_ERR_NO_ERROR)
    {
        errorcode = OSPPPKCS8KeyInfoGetPrivateKeyElement(ospvPrivateKeyInfo, 
            OSPEDRID_PVTKEYINF_PRIVATEKEY,
            &eInfo);

    }
    if (errorcode == OSPC_ERR_NO_ERROR)
    {
        errorcode = OSPPASN1ElementGetContentData(eInfo, 
            ospvPrivateKey, ospvPrivateKeyLength);
    }

    return errorcode;
}



int
OSPPPKCS8KeyInfoGetPrivateKeyElement(
    OSPTASN1OBJECT *ospvPrivateKeyInfo, 
    OSPEASN1DATAREFID ospvDataRefId,
    OSPTASN1ELEMENTINFO **ospvElementInfo)
{
    int                 errorcode       = OSPC_ERR_NO_ERROR;
    OSPTASN1ELEMENTINFO *foundElement   = OSPC_OSNULL;

    errorcode = OSPPPKCS8KeyInfoTestContext(ospvPrivateKeyInfo);

    if (errorcode == OSPC_ERR_NO_ERROR)
    {
        errorcode = OSPPASN1ElementGet(ospvDataRefId, 
            ospvPrivateKeyInfo->ParseResults, &foundElement);
    }

    *ospvElementInfo = foundElement;

    return errorcode;
}


