//-------------------------------------------------------------------------
//
//  Microsoft Windows
//
//  Copyright (C) Microsoft Corporation, 1995 - 1999
//
//  File:       tcrack.cpp
//
//  Contents:   API testing of CryptEncodeObject/CryptDecodeObject.
//
//  History:    29-January-97   xiaohs   created
//
//--------------------------------------------------------------------------
#include "global.hxx"

//--------------------------------------------------------------------------
//  See if the sequence "81 7f" is in the BLOB.  If it is, we need to fix it
//--------------------------------------------------------------------------
BOOL    BadCert(DWORD   cbEncoded, BYTE *pbEncoded)
{
    DWORD   iIndex=0;
    DWORD   iLimit=cbEncoded-2;
    BYTE    rgByte[2];


    assert(pbEncoded);


    memset(rgByte, 0, 2);

    //set the rgByte to be the patter of 0x81 0x7F, which is 10000001 and 01111111,
    //whic his 129 and 127 in decimal
    rgByte[0]=rgByte[0]|129;
    rgByte[1]=rgByte[1]|127;


    for(iIndex=0;iIndex<=iLimit;iIndex++)
    {
        if(memcmp(rgByte,&(pbEncoded[iIndex]),2)==0)
            return TRUE;
    }

    return FALSE;

}

//--------------------------------------------------------------------------
//  Copy the BLOBs
//--------------------------------------------------------------------------
void    SetData(DWORD   cbNewData, BYTE *pbNewData,
                DWORD   *pcbOldData, BYTE **ppbOldData)
{
    assert(pcbOldData);
    assert(ppbOldData);

    *pcbOldData=cbNewData;
    *ppbOldData=pbNewData;
}


///////////////////////////////////////////////////////////////////////////
//Certificate Manipulation Functions
//--------------------------------------------------------------------------
//  This is the functions
//--------------------------------------------------------------------------
BOOL    Fix7FCert(DWORD cbEncoded, BYTE *pbEncoded, DWORD *pcbEncoded,
                        BYTE    **ppbEncoded)
{

    //init
    *pcbEncoded=0;
    *ppbEncoded=NULL;



    if(!BadCert(cbEncoded, pbEncoded))
        return TRUE;


    if(DecodeX509_CERT(cbEncoded, pbEncoded,pcbEncoded,
                        ppbEncoded))
        return TRUE;
    else
    {
        //release the memory
        SAFE_FREE(*ppbEncoded)
        *ppbEncoded=NULL;
        *pcbEncoded=0;
        return FALSE;
    }


}

//--------------------------------------------------------------------------
//  A general routine to encode a struct based on lpszStructType
//--------------------------------------------------------------------------
BOOL    EncodeStruct(LPCSTR lpszStructType, void *pStructInfo,DWORD *pcbEncoded,
                     BYTE **ppbEncoded)
{
    BOOL    fSucceeded=FALSE;
    DWORD   cbEncoded=NULL;

    //init
    *pcbEncoded=0;
    *ppbEncoded=NULL;

    assert(lpszStructType);
    assert(pStructInfo);


    //length only calculation
    TESTC(CryptEncodeObject(CRYPT_ENCODE_TYPE,lpszStructType, pStructInfo,NULL,
            &cbEncoded),TRUE)

    //the struct has to be more than 0 byte
    assert(cbEncoded);

    //allocate the correct amount of memory
    *ppbEncoded=(BYTE *)SAFE_ALLOC(cbEncoded);
    CHECK_POINTER(*ppbEncoded);

    //Encode the strcut with *pcbEncoded == the correct length
    *pcbEncoded=cbEncoded;

    //Encode the struct
    TESTC(CryptEncodeObject(CRYPT_ENCODE_TYPE,lpszStructType,pStructInfo,*ppbEncoded,
        pcbEncoded),TRUE)

    fSucceeded=TRUE;

TCLEANUP:

    return fSucceeded;

}

//--------------------------------------------------------------------------
//  A general routine to decode a BLOB based on lpszStructType
//
//--------------------------------------------------------------------------
BOOL  DecodeBLOB(LPCSTR lpszStructType,DWORD cbEncoded, BYTE *pbEncoded,
                  DWORD *pcbStructInfo, void **ppvStructInfo)
{
    BOOL    fSucceeded=FALSE;
    DWORD   cbStructInfo=0;

    //init
    *pcbStructInfo=0;
    *ppvStructInfo=NULL;

    assert(lpszStructType);
    assert(pbEncoded);
    assert(cbEncoded);

    //Decode.  Length Only Calculation
    TESTC(CryptDecodeObject(CRYPT_ENCODE_TYPE,lpszStructType,pbEncoded,cbEncoded,
    CRYPT_DECODE_FLAG,NULL,&cbStructInfo),TRUE)

    //the struct has to be more than 0 byte
    assert(cbStructInfo);

    *ppvStructInfo=(BYTE *)SAFE_ALLOC(cbStructInfo);
    CHECK_POINTER(*ppvStructInfo);

    //Decode the BLOB with *pcbStructInfo==correct length
    *pcbStructInfo=cbStructInfo;

    TESTC(CryptDecodeObject(CRYPT_ENCODE_TYPE,lpszStructType,pbEncoded,cbEncoded,
    CRYPT_DECODE_FLAG,*ppvStructInfo,pcbStructInfo),TRUE)


    fSucceeded=TRUE;

TCLEANUP:

    return fSucceeded;

}

//--------------------------------------------------------------------------
//  Decode X509_CERT BLOBs
//
//--------------------------------------------------------------------------
BOOL    DecodeX509_CERT(DWORD cbEncoded, BYTE *pbEncoded,DWORD *pcbEncoded,
                        BYTE    **ppbEncoded)
{
    BOOL    fSucceeded=FALSE;
    DWORD   cbStructInfo=0;
    void    *pStructInfo=NULL;
    LPCSTR  lpszStructType=NULL;
    DWORD   cbToBeSigned=0;
    BYTE    *pbToBeSigned=NULL;
    DWORD   cbOldSigned=0;
    BYTE    *pbOldSigned=NULL;

    //init
    lpszStructType=X509_CERT;


    //Decode the encoded BLOB
    TESTC(DecodeBLOB(lpszStructType,cbEncoded, pbEncoded,&cbStructInfo,
        &pStructInfo),TRUE)

    //Further Decode the X509_CERT_TO_BE_SIGNED
    //Notice we should use the original cbData and pbData passed in for Decode
    //but use ToBeSigned in CERT_SIGNED_CONTENT_INFO for encode purpose

    TESTC(DecodeX509_CERT_TO_BE_SIGNED(cbEncoded,
        pbEncoded,&cbToBeSigned,&pbToBeSigned),TRUE);

    //copy the new encoded BLOB
    SetData((((PCERT_SIGNED_CONTENT_INFO)pStructInfo)->ToBeSigned).cbData,
               (((PCERT_SIGNED_CONTENT_INFO)pStructInfo)->ToBeSigned).pbData,
               &cbOldSigned, &pbOldSigned);

    SetData(cbToBeSigned, pbToBeSigned,
                &((((PCERT_SIGNED_CONTENT_INFO)pStructInfo)->ToBeSigned).cbData),
                &((((PCERT_SIGNED_CONTENT_INFO)pStructInfo)->ToBeSigned).pbData));


    //if requested, encode the BLOB back to what it was.  Make sure no data is lost
    //by checking the size of the encoded blob and do a memcmp.
    TESTC(EncodeStruct(lpszStructType, pStructInfo,pcbEncoded, ppbEncoded),TRUE);

    fSucceeded=TRUE;

TCLEANUP:

    SetData(cbOldSigned, pbOldSigned,
            &((((PCERT_SIGNED_CONTENT_INFO)pStructInfo)->ToBeSigned).cbData),
            &((((PCERT_SIGNED_CONTENT_INFO)pStructInfo)->ToBeSigned).pbData));


    SAFE_FREE(pStructInfo)

    SAFE_FREE(pbToBeSigned)

    return fSucceeded;

}



//--------------------------------------------------------------------------
//  Decode X509_CERT_TO_BE_SIGNED BLOBs
//
//--------------------------------------------------------------------------
BOOL    DecodeX509_CERT_TO_BE_SIGNED(DWORD  cbEncoded, BYTE *pbEncoded, DWORD *pcbEncoded,
                        BYTE    **ppbEncoded)
{

    BOOL    fSucceeded=FALSE;
    DWORD   cbStructInfo=0;
    void    *pStructInfo=NULL;
    LPCSTR  lpszStructType=NULL;


    DWORD   cbOldIssuer=0;
    BYTE    *pbOldIssuer=NULL;
    DWORD   cbIssuer=0;
    BYTE    *pbIssuer=NULL;


    DWORD   cbOldSubject=0;
    BYTE    *pbOldSubject=NULL;
    DWORD   cbSubject=0;
    BYTE    *pbSubject=NULL;


    //init
    lpszStructType=X509_CERT_TO_BE_SIGNED;


    //Decode the encoded BLOB
    TESTC(DecodeBLOB(lpszStructType,cbEncoded, pbEncoded,&cbStructInfo,
        &pStructInfo),TRUE)


      //Decode Issuer in CERT_INFO struct
    TESTC(DecodeX509_NAME((((PCERT_INFO)pStructInfo)->Issuer).cbData,
    (((PCERT_INFO)pStructInfo)->Issuer).pbData,&cbIssuer,&pbIssuer),TRUE)

    SetData((((PCERT_INFO)pStructInfo)->Issuer).cbData,
            (((PCERT_INFO)pStructInfo)->Issuer).pbData,&cbOldIssuer,&pbOldIssuer);

    SetData(cbIssuer, pbIssuer,
            &((((PCERT_INFO)pStructInfo)->Issuer).cbData),
            &((((PCERT_INFO)pStructInfo)->Issuer).pbData));



    //Decode Subject in CERT_INFO struct
    TESTC(DecodeX509_NAME((((PCERT_INFO)pStructInfo)->Subject).cbData,
    (((PCERT_INFO)pStructInfo)->Subject).pbData,&cbSubject,&pbSubject),TRUE)

    SetData((((PCERT_INFO)pStructInfo)->Subject).cbData,
    (((PCERT_INFO)pStructInfo)->Subject).pbData,
    &cbOldSubject, &pbOldSubject);

    SetData(cbSubject, pbSubject,
        &((((PCERT_INFO)pStructInfo)->Subject).cbData),
        &((((PCERT_INFO)pStructInfo)->Subject).pbData));




    //if requested, encode the BLOB back to what it was.  Make sure no data is lost
    //by checking the size of the encoded blob and do a memcmp.
    TESTC(EncodeStruct(lpszStructType, pStructInfo,pcbEncoded,
        ppbEncoded),TRUE);



    fSucceeded=TRUE;

TCLEANUP:

    //copy back the old values
    SetData(cbOldSubject, pbOldSubject,
        &((((PCERT_INFO)pStructInfo)->Subject).cbData),
        &((((PCERT_INFO)pStructInfo)->Subject).pbData));


    SetData(cbOldIssuer, pbOldIssuer,
            &((((PCERT_INFO)pStructInfo)->Issuer).cbData),
            &((((PCERT_INFO)pStructInfo)->Issuer).pbData));



    SAFE_FREE(pStructInfo)

    SAFE_FREE(pbSubject)

    SAFE_FREE(pbIssuer)

    return fSucceeded;

}

//--------------------------------------------------------------------------
//  Decode X509_NAME BLOBs
//
//--------------------------------------------------------------------------
BOOL    DecodeX509_NAME(DWORD   cbEncoded, BYTE *pbEncoded, DWORD *pcbEncoded,
                        BYTE    **ppbEncoded)
{

    BOOL    fSucceeded=FALSE;
    DWORD   cbStructInfo=0;
    void    *pStructInfo=NULL;
    LPCSTR  lpszStructType=NULL;


    //init
    lpszStructType=X509_NAME;


    //Decode the encoded BLOB
    TESTC(DecodeBLOB(lpszStructType,cbEncoded, pbEncoded,&cbStructInfo,
        &pStructInfo),TRUE)


    //if requested, encode the BLOB back to what it was.  Make sure no data is lost
    //by checking the size of the encoded blob and do a memcmp.
    TESTC(EncodeStruct(lpszStructType, pStructInfo,pcbEncoded, ppbEncoded),TRUE);


    fSucceeded=TRUE;

TCLEANUP:

    SAFE_FREE(pStructInfo)

    return fSucceeded;

}



