sources/ASIPChallenge.cp

//  ASIPChallenge.cp - base class for Appleshare IP Challenge Object
// 
// Apple Macintosh Developer Technical Support
// Written by:  Vinnie Moscaritolo
//
//  Copyright (work in progress)  Apple Computer, Inc All rights reserved.
//
// You may incorporate this sample code into your applications without
// restriction, though the sample code has been provided "AS IS" and the
// responsibility for its operation is 100% yours.  However, what you are
// not permitted to do is to redistribute the source as "DSC Sample Code"
// after having made changes. If you're going to re-distribute the source,
// we require that you make it clear in the source that the code was
// descended from Apple Sample Code, but that you've made changes.
// 
 
 
#include <string.h>
#include <TextUtils.h>
#include <PLStringFuncs.h>
 
#include "ASIPChallenge.h"
#include "PassphraseCache.h"
#include "TPGPException.h"
 
#include "pgpRandomPool.h"
#include "pgpUserInterface.h"
 
 
// ---------------------------------------------------------------------------
void  MakeChallenge(TPGPkey *theKey, StringPtr outBuf)
// ---------------------------------------------------------------------------
//   
//    outBuf        --> [len][challenge]  
{
 
    PGPSize challengeSize;
    PGPError err;
        
    challengeSize = theKey->GetHashSize();
 
    while ((err = PGPContextGetRandomBytes(TPGPkey::fgContext, &outBuf[1], challengeSize)) == kPGPError_OutOfEntropy  )
    {
// handle entropy errors?
// what about no UI?
        ThrowIfPGPErr(
            PGPCollectRandomDataDialog(TPGPkey::fgContext, 
                PGPGlobalRandomPoolGetMinimumEntropy() - PGPGlobalRandomPoolGetEntropy(), 
                PGPOLastOption(TPGPkey::fgContext )));
    }
    ThrowIfPGPErr(err); 
 
    outBuf[0] = challengeSize & 0xFF;
 
}
 
 
#define counterChallengeSize  64
 
// ---------------------------------------------------------------------------
void ReplyToChallenge(TPGPkey *serverKey, const char *passPhrase, TPGPkey *clientKey, StringPtr inBuf, StringPtr outBuf)
// ---------------------------------------------------------------------------
//   
//    inBuf     --> [len][challenge]  
//
//    outBuf    <-- [len of total][offset to orig challenge][counterchallenge] [sig]
        
{
 
    UInt8   *counterChallenge = (UInt8*) outBuf + 1;
    UInt8   offset;
    PGPSize sigBufSize = 0;
        
    ThrowPGPErrIfTrue( clientKey->GetHashSize() * 2 > counterChallengeSize , kPGPError_BufferTooSmall);
        
// calculate counter challenge string
    PGPContextGetRandomBytes(TPGPkey::fgContext, counterChallenge, counterChallengeSize );
 
// offset the challenge into the counterchallenge
    offset =  counterChallengeSize - inBuf[0] - (counterChallenge[0] & 0x1F); 
    ThrowPGPErrIfTrue ( offset < 1, kPGPError_BufferTooSmall);
    counterChallenge[0] = offset;
    memcpy(&counterChallenge[offset], inBuf+1, inBuf[0]);
 
 // sign  the counter challenge
    if(serverKey && serverKey->CanSign() )
        serverKey->Sign(counterChallenge, counterChallengeSize , counterChallenge + counterChallengeSize, &sigBufSize, passPhrase);
        
    outBuf[0] = (sigBufSize & 0xFF) + 64;
    
 
}
 
 
// ---------------------------------------------------------------------------
Boolean VerifyChallenge(TPGPkey *theKey,StringPtr origChallenge, StringPtr inBuf)
// ---------------------------------------------------------------------------
//   
//    origChallenge     <-- [len][challenge]  
//    inBuf             <-- [len of total][offset to orig challenge][counterchallenge] [sig]
//
{
    
    // check if challenge string is correct.
    if(!(memcmp(  &inBuf[ inBuf[1] + 1] , &origChallenge[1], origChallenge[0]) == 0 )) 
        return false;
    
    // check sig
    return theKey->Verify(  &inBuf[1], 64,  &inBuf[65], inBuf[0] - 64);
  
}
 
// ---------------------------------------------------------------------------
PGPError ReplyToCounterChallenge(StringPtr promptString, StringPtr fpBuf, StringPtr inBuf, StringPtr outBuf)
// ---------------------------------------------------------------------------
//   
//    fpBuf         <-- [len][fingerprint of challenged]  
//    inBuf         <-- [len of total][offset to orig challenge][counterchallenge] [sig]
//    outbuf        --> [len of sig] [sig]
//
//
{
    PGPFilterRef    theFilter       = kInvalidPGPFilterRef;
    PGPKeyIterRef   theIterator     = kInvalidPGPKeyIterRef;
    PGPKeyListRef   theKeyListRef   = kInvalidPGPKeyListRef;
    PGPKeyRef       theKeyRef       = kInvalidPGPKeyRef;
    PGPOptionListRef optionList     = kInvalidPGPOptionListRef;
    PGPContextRef   context         = TPGPkey::fgContext;
    PGPKeySetRef    newKeySet       = NULL;
    PGPUInt32       numKeys;
    PGPError        err             = noErr;            
 
// Find key in database
    ThrowIfPGPErr( PGPNewKeyFingerPrintFilter(TPGPkey::fgContext,&fpBuf[1],fpBuf[0] , &theFilter));
    ThrowIfPGPErr( PGPFilterKeySet(TPGPkey::fgPGPKeySetRef , theFilter, &newKeySet));
    PGPFreeFilter(theFilter);
    ThrowIfPGPErr( PGPCountKeys(newKeySet, &numKeys));
 
    if(numKeys != 1) 
        err = kPGPError_KeyInvalid;
    else
    {   
        unsigned char   promptStr[256];
        char *thePassphrase = NULL;
 
        ThrowIfPGPErr( PGPOrderKeySet(newKeySet,kPGPAnyOrdering, &theKeyListRef));
        ThrowIfPGPErr( PGPNewKeyIter( theKeyListRef, &theIterator ));
        ThrowIfPGPErr( PGPKeyIterNext( theIterator, &theKeyRef ));
        
        ThrowIfPGPErr ( PGPBuildOptionList( context, &optionList,
                            PGPOUIOutputPassphrase(context, &thePassphrase),
                            PGPOUIDefaultKey(context, theKeyRef),
                            PGPOUIVerifyPassphrase(context, true),
                            PGPOLastOption(context) ));
 
        if(promptString) 
        {
            ThrowIfPGPErr ( PGPAppendOptionList( optionList,
                            PGPOUIDialogPrompt(context, (char *)promptString),
                            PGPOLastOption(context) ));
        };
        
        if( GetPassphrase(TPGPkey::fgContext, theKeyRef, &thePassphrase) 
            || (  (err = PGPSigningPassphraseDialog(context, newKeySet, &theKeyRef,
                            optionList,
                            PGPOLastOption(TPGPkey::fgContext ))) ==  kPGPError_NoErr )
            && (RememberPassphrase(theKeyRef, thePassphrase), true))
        {
            TPGPkey theKey;
            PGPSize sigBufSize;
            
            theKey.Initialize(theKeyRef);
            
            if( theKey.IsOperational())
            {
                if( ! theKey.Sign(&inBuf[1], 64, &outBuf[1], &sigBufSize, thePassphrase))
                    err = kPGPError_KeyInvalid;
                outBuf[0] = (sigBufSize & 0xFF);
            }                       
         
            // Erase passphrase                                 
            PGPFreeData(thePassphrase);
            thePassphrase = NULL;
        }
        
        if(err == kPGPError_UserAbort) err = userCanceledErr;
    
    }
    PGPFreeOptionList(optionList);
    PGPFreeKeyIter(theIterator );
    PGPFreeKeyList(theKeyListRef );
    PGPFreeKeySet(newKeySet );
 
    return err;
}
 
 
// ---------------------------------------------------------------------------
Boolean VerifyCounterChallenge(TPGPkey *theKey, StringPtr origCounterChallenge, StringPtr inBuf)
// ---------------------------------------------------------------------------
//   
//    origCounterChallenge  <-- [len of total][offset to orig challenge][counterchallenge] [sig]
//    inBuf                 <-- [len of sig] [sig]
 
{
 
        return theKey->Verify(  &origCounterChallenge[1], 64,   &inBuf[1], inBuf[0]);
 
}