home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / crypl200.zip / LIB_PKCS.C < prev    next >
Text File  |  1996-09-30  |  23KB  |  620 lines

  1. /****************************************************************************
  2. *                                                                            *
  3. *                        cryptlib PKCS Interface Routines                    *
  4. *                        Copyright Peter Gutmann 1993-1996                    *
  5. *                                                                            *
  6. ****************************************************************************/
  7.  
  8. #include <string.h>
  9. #include <stdlib.h>
  10. #include "crypt.h"
  11. #ifdef INC_ALL
  12.   #include "asn1objs.h"
  13. #else
  14.   #include "keymgmt/asn1objs.h"
  15. #endif /* Compiler-specific includes */
  16.  
  17. /* The following routines try to keep the amount of time in which sensitive
  18.    information is present in buffers to an absolute minimum (although the
  19.    buffers are pagelocked on most OS's, there are some systems where this
  20.    isn't possible).  The code is structured to keep the operations which
  21.    create and those which use sensitive information in memory as close
  22.    together as possible and to clear the memory as soon as it's used.  For
  23.    this reason the structure is somewhat unusual, with everything in one
  24.    linear block of code with jumps to clearly-defined locations to exit the
  25.    current nesting level in the case of errors.  This is necessary to ensure
  26.    that the approriate cleanup operations are performed at each level, and
  27.    that the in-memory data is destroyed as soon as possible - the prime goal
  28.    is to destroy the data as soon as we can.  Security-conscious code isn't
  29.    necessary cleanly-structured code */
  30.  
  31. /****************************************************************************
  32. *                                                                            *
  33. *                            Create/Check a Signature                         *
  34. *                                                                            *
  35. ****************************************************************************/
  36.  
  37. /* Create a signature for a block of data */
  38.  
  39. CRET cryptCreateSignature( void CPTR signature, int CPTR signatureLength,
  40.                            const CRYPT_CONTEXT pkcContext,
  41.                            const CRYPT_CONTEXT hashContext )
  42.     {
  43.     CRYPT_INFO *hashInfoPtr = CONTEXT_TO_INFO( hashContext );
  44.     CRYPT_INFO *pkcInfoPtr = CONTEXT_TO_INFO( pkcContext );
  45.     CRYPT_QUERY_INFO hashQueryInfo;
  46.     BYTE dataToSign[ CRYPT_MAX_PKCSIZE ];
  47.     MESSAGE_DIGEST hash;
  48.     STREAM stream;
  49.     int length, payloadSize, status, i;
  50.  
  51.     /* Perform basic error checking */
  52.     if( signatureLength == NULL )
  53.         return( CRYPT_BADPARM2 );
  54.     if( isBadCookie( pkcContext ) || pkcInfoPtr->checkValue != CRYPT_MAGIC || \
  55.         !pkcInfoPtr->isPKCcontext || pkcInfoPtr->isPublicKey )
  56.         return( CRYPT_BADPARM3 );
  57.     if( isBadCookie( hashContext ) || hashInfoPtr->checkValue != CRYPT_MAGIC || \
  58.         hashInfoPtr->capabilityInfo->cryptMode != CRYPT_MODE_NONE )
  59.         return( CRYPT_BADPARM4 );
  60.     if( !pkcInfoPtr->keySet )
  61.         return( CRYPT_NOKEY );
  62.     if( pkcInfoPtr->capabilityInfo->encryptFunction == NULL )
  63.         return( CRYPT_NOALGO );
  64.     length = bitsToBytes( pkcInfoPtr->keySizeBits );
  65.  
  66.     /* If we're just doing a length check, write the data to a null stream
  67.        and return its length */
  68.     if( signature == NULL )
  69.         {
  70.         STREAM nullStream;
  71.  
  72.         sMemNullOpen( &nullStream );
  73.         status = writeSignature( &nullStream, pkcInfoPtr, dataToSign, length );
  74.         *signatureLength = sMemSize( &nullStream );
  75.         sMemClose( &nullStream );
  76.  
  77.         return( status );
  78.         }
  79.  
  80.     /* Extract the hash information from the hash context, turn it into a
  81.        message digest record, and find out how much space we need to
  82.        allocate to it in the signature record.  There's no need for a length
  83.        check as there is for the key export function since even the largest
  84.        hash fits easily within the shortest PKC key the library allows */
  85.     if( cryptQueryContext( hashContext, &hashQueryInfo ) != CRYPT_OK )
  86.         return( CRYPT_BADPARM4 );
  87.     newMessageDigest( &hash, hashQueryInfo.cryptAlgo,
  88.                       hashQueryInfo.hashValue, hashQueryInfo.blockSize );
  89.     payloadSize = sizeofMessageDigestInfo( &hash );
  90.     zeroise( &hashQueryInfo, sizeof( CRYPT_QUERY_INFO ) );
  91.  
  92.     /* Encode the payload using the format given in PKCS #1.  The format for
  93.        signed data is [ 0 ][ 1 ][ 0xFF padding ][ 0 ][ payload ] which is
  94.        done by the following code */
  95.     sMemOpen( &stream, dataToSign, CRYPT_MAX_PKCSIZE );
  96.     sputc( &stream, 0 );
  97.     sputc( &stream, 1 );
  98.     for( i = 0; i < length - ( payloadSize + 3 ); i++ )
  99.         sputc( &stream, 0xFF );
  100.     sputc( &stream, 0 );
  101.     writeMessageDigestInfo( &stream, &hash );
  102.     deleteMessageDigest( &hash );
  103.  
  104.     /* Sign the data by decrypting it with the private key */
  105.     status = pkcInfoPtr->capabilityInfo->decryptFunction( pkcInfoPtr, dataToSign, length );
  106.  
  107.     /* Write the signature record to the output and clean up */
  108.     if( cryptStatusOK( status ) )
  109.         {
  110.         STREAM outputStream;
  111.  
  112.         sMemOpen( &outputStream, signature, STREAMSIZE_UNKNOWN );
  113.         status = writeSignature( &outputStream, pkcInfoPtr, dataToSign, length );
  114.         *signatureLength = sMemSize( &outputStream );
  115.         sMemDisconnect( &outputStream );
  116.         }
  117.     sMemClose( &stream );
  118.  
  119.     return( status );
  120.     }
  121.  
  122. /* Check a signature on a block of data */
  123.  
  124. CRET cryptCheckSignature( const void CPTR signature,
  125.                           const CRYPT_CONTEXT pkcContext,
  126.                           const CRYPT_CONTEXT hashContext )
  127.     {
  128.     CRYPT_INFO *hashInfoPtr = CONTEXT_TO_INFO( hashContext );
  129.     CRYPT_INFO *pkcInfoPtr = CONTEXT_TO_INFO( pkcContext );
  130.     CRYPT_QUERY_INFO hashQueryInfo;
  131.     BYTE decryptedSignature[ CRYPT_MAX_PKCSIZE ];
  132.     STREAM stream;
  133.     int length, status;
  134.  
  135.     /* Perform basic error checking */
  136.     if( signature == NULL )
  137.         return( CRYPT_BADPARM1 );
  138.     if( isBadCookie( pkcContext ) || pkcInfoPtr->checkValue != CRYPT_MAGIC || \
  139.         !pkcInfoPtr->isPKCcontext )
  140.         return( CRYPT_BADPARM2 );
  141.     if( isBadCookie( hashContext ) || hashInfoPtr->checkValue != CRYPT_MAGIC || \
  142.         hashInfoPtr->capabilityInfo->cryptMode != CRYPT_MODE_NONE )
  143.         return( CRYPT_BADPARM3 );
  144.     if( !pkcInfoPtr->keySet )
  145.         return( CRYPT_NOKEY );
  146.     if( pkcInfoPtr->capabilityInfo->decryptFunction == NULL )
  147.         return( CRYPT_NOALGO );
  148.  
  149.     /* Get information on the hash context */
  150.     if( cryptQueryContext( hashContext, &hashQueryInfo ) != CRYPT_OK )
  151.         return( CRYPT_BADPARM3 );
  152.     length = bitsToBytes( pkcInfoPtr->keySizeBits );
  153.  
  154.     /* Read the signature record up to the start of the encrypted key */
  155.     sMemConnect( &stream, ( void * ) signature, STREAMSIZE_UNKNOWN );
  156.     status = readSignature( &stream, pkcInfoPtr );
  157.     if( cryptStatusError( status ) )
  158.         goto endCheckSignature;
  159.  
  160.     /* Recover the data by encrypting the signature with the public key */
  161.     memcpy( decryptedSignature, ( BYTE * ) signature + sMemSize( &stream ), length );
  162.     status = pkcInfoPtr->capabilityInfo->encryptFunction( pkcInfoPtr, decryptedSignature, length );
  163.     if( cryptStatusOK( status ) )
  164.         {
  165.         MESSAGE_DIGEST hash;
  166.         STREAM inputStream;
  167.         int ch, i;
  168.  
  169.         newMessageDigest( &hash, CRYPT_ALGO_NONE, NULL, 0 );
  170.  
  171.         /* Undo the PKCS #1 padding.  The PKCS format for signed data is
  172.            [ 0 ][ 1 ][ 0xFF padding ][ 0 ][ payload ] which is checked for by
  173.            the following code */
  174.         sMemConnect( &inputStream, decryptedSignature, length );
  175.         if( sgetc( &inputStream ) != 0 || sgetc( &inputStream ) != 1 )
  176.             {
  177.             status = CRYPT_BADDATA;
  178.             goto endCheckSignatureInfo;
  179.             }
  180.         for( i = 0; i < length - 3; i++ )
  181.             if( ( ch = sgetc( &inputStream ) ) != 0xFF )
  182.                 break;
  183.         if( ch != 0 || readMessageDigestInfo( &inputStream, &hash ) < 0 )
  184.             {
  185.             status = CRYPT_BADDATA;
  186.             goto endCheckSignatureInfo;
  187.             }
  188.  
  189.         /* Finally, make sure the two hash values match */
  190.         if( hashQueryInfo.cryptAlgo != hash.type ||
  191.             memcmp(    hash.data, hashQueryInfo.hashValue, hashQueryInfo.blockSize ) )
  192.             status = CRYPT_BADSIG;
  193.  
  194.         /* Clean up */
  195. endCheckSignatureInfo:
  196.         deleteMessageDigest( &hash );
  197.         sMemClose( &inputStream );
  198.         }
  199. endCheckSignature:
  200.     zeroise( &hashQueryInfo, sizeof( CRYPT_QUERY_INFO ) );
  201.     sMemDisconnect( &stream );
  202.  
  203.     return( status );
  204.     }
  205.  
  206. /****************************************************************************
  207. *                                                                            *
  208. *                Import/Export a Conventional or PKC-Encrypted Key            *
  209. *                                                                            *
  210. ****************************************************************************/
  211.  
  212. /* Export a conventional-encrypted session key.  This is seperated out from
  213.    the main cryptExportKey() code because the conventional and PKC export
  214.    code is completely different, even though it's called via the same API */
  215.  
  216. static int exportConventionalKey( void *encryptedKey, int *encryptedKeyLength,
  217.                                   CRYPT_CONTEXT cryptContext,
  218.                                   const CRYPT_INFO *sessionKeyInfoPtr )
  219.     {
  220.     CRYPT_INFO *cryptInfoPtr = CONTEXT_TO_INFO( cryptContext );
  221.     STREAM stream;
  222.     BYTE *buffer;
  223.     int status, keyOffset;
  224.  
  225.     /* If we're just doing a length check, write the data to a null stream
  226.        and return its length */
  227.     if( encryptedKey == NULL )
  228.         {
  229.         STREAM nullStream;
  230.         BYTE dummyBuffer[ CRYPT_MAX_PKCSIZE ];    /* See note below */
  231.  
  232.         sMemNullOpen( &nullStream );
  233.         status = writeEncryptedKey( &nullStream, cryptInfoPtr,
  234.                                     sessionKeyInfoPtr, dummyBuffer,
  235.                                     sizeofKeyInfo( sessionKeyInfoPtr, TRUE ) );
  236.         *encryptedKeyLength = sMemSize( &nullStream );
  237.         sMemClose( &nullStream );
  238.  
  239.         return( status );
  240.         }
  241.  
  242.     /* Initialise various things (the use of CRYPT_MAX_PKCSIZE isn't
  243.        strictly appropriate here, but it's a good indication of the amount
  244.        of memory needed) */
  245.     if( ( status = secureMalloc( ( void ** ) &buffer, CRYPT_MAX_PKCSIZE ) ) != CRYPT_OK )
  246.         return( status );
  247.     sMemOpen( &stream, buffer, CRYPT_MAX_PKCSIZE );
  248.  
  249.     /* Write the key information into the buffer and encrypt it */
  250.     status = writeKeyInfo( &stream, sessionKeyInfoPtr, &keyOffset, TRUE );
  251.     if( cryptStatusOK( status ) )
  252.         {
  253.         /* Copy the key in at the last possible moment, then encrypt it */
  254.         memcpy( buffer + keyOffset, sessionKeyInfoPtr->userKey,
  255.                 sessionKeyInfoPtr->userKeyLength );
  256.         status = cryptEncrypt( cryptContext, buffer, sMemSize( &stream ) );
  257.         }
  258.  
  259.     /* Now write the encrypted key to the output stream */
  260.     if( cryptStatusOK( status ) )
  261.         {
  262.         STREAM outputStream;
  263.  
  264.         sMemOpen( &outputStream, encryptedKey, STREAMSIZE_UNKNOWN );
  265.         status = writeEncryptedKey( &outputStream, cryptInfoPtr,
  266.                                     sessionKeyInfoPtr, buffer,
  267.                                     sMemSize( &stream ) );
  268.         *encryptedKeyLength = sMemSize( &outputStream );
  269.         sMemDisconnect( &outputStream );
  270.         }
  271.  
  272.     /* Clean up */
  273.     secureFree( ( void ** ) &buffer );
  274.     sMemClose( &stream );
  275.     return( status );
  276.     }
  277.  
  278. /* Export an encrypted session key */
  279.  
  280. CRET cryptExportKey( void CPTR encryptedKey, int CPTR encryptedKeyLength,
  281.                      const CRYPT_CONTEXT cryptContext,
  282.                      const CRYPT_CONTEXT sessionKeyContext )
  283.     {
  284.     CRYPT_INFO *cryptInfoPtr = CONTEXT_TO_INFO( cryptContext );
  285.     CRYPT_INFO *sessionKeyInfoPtr = CONTEXT_TO_INFO( sessionKeyContext );
  286.     CRYPT_ALGO cryptAlgo;
  287.     STREAM stream;
  288.     BYTE *buffer;
  289.     int length, status, payloadSize, i;
  290.  
  291.     /* Perform basic error checking */
  292.     if( encryptedKeyLength == NULL )
  293.         return( CRYPT_BADPARM2 );
  294.     if( isBadCookie( cryptContext ) || \
  295.         cryptInfoPtr->checkValue != CRYPT_MAGIC )
  296.         return( CRYPT_BADPARM3 );
  297.     if( isBadCookie( sessionKeyContext ) || \
  298.         sessionKeyInfoPtr->checkValue != CRYPT_MAGIC || \
  299.         sessionKeyInfoPtr->isPKCcontext || \
  300.         sessionKeyInfoPtr->capabilityInfo->cryptMode == CRYPT_MODE_NONE )
  301.         return( CRYPT_BADPARM4 );
  302.     cryptAlgo = cryptInfoPtr->capabilityInfo->cryptAlgo;
  303.     if( !cryptInfoPtr->keySet || \
  304.         ( cryptAlgo != CRYPT_ALGO_DH && !sessionKeyInfoPtr->keySet ) )
  305.         return( CRYPT_NOKEY );
  306.     if( cryptInfoPtr->capabilityInfo->encryptFunction == NULL )
  307.         return( CRYPT_NOALGO );
  308.  
  309.     /* If it's a conventional encryption context, export it as such */
  310.     if( !cryptInfoPtr->isPKCcontext )
  311.         return( exportConventionalKey( encryptedKey, encryptedKeyLength,
  312.                                        cryptContext, sessionKeyInfoPtr ) );
  313.  
  314.     /* Evaluate the size of the encrypted information if it's a conventional
  315.        PKC and make sure the key is long enough to encrypt the payload.
  316.        PKCS #1 requires that the maximum payload size be 11 bytes less than
  317.        the length (to give a minimum of 8 bytes of random padding) */
  318.     length = bitsToBytes( cryptInfoPtr->keySizeBits );
  319.     if( cryptAlgo != CRYPT_ALGO_DH )
  320.         {
  321.         payloadSize = sizeofKeyInfo( sessionKeyInfoPtr, FALSE );
  322.         if( payloadSize > length - 11 )
  323.             return( CRYPT_DATASIZE );
  324.         }
  325.  
  326.     /* If we're just doing a length check, write the data to a null stream
  327.        and return its length */
  328.     if( encryptedKey == NULL )
  329.         {
  330.         STREAM nullStream;
  331.         BYTE dummyBuffer[ CRYPT_MAX_PKCSIZE ];
  332.  
  333.         sMemNullOpen( &nullStream );
  334.         status = writePKCEncryptedKey( &nullStream, cryptInfoPtr,
  335.                                        sessionKeyInfoPtr, dummyBuffer, length );
  336.         *encryptedKeyLength = sMemSize( &nullStream );
  337.         sMemClose( &nullStream );
  338.  
  339.         return( status );
  340.         }
  341.  
  342.     /* Initialise various things */
  343.     if( ( status = secureMalloc( ( void ** ) &buffer, CRYPT_MAX_PKCSIZE ) ) != CRYPT_OK )
  344.         return( status );
  345.     sMemOpen( &stream, buffer, length );
  346.  
  347.     /* Diffie-Hellman and conventional PKC's are treated slightly
  348.        differently since DH can't embed information in the shared secret */
  349.     if( cryptAlgo == CRYPT_ALGO_DH )
  350.         {
  351.         /* For Diffie-Hellman we can't convey any information in the
  352.            encrypted data, so we simply encrypt a buffer full of random data */
  353.         for( i = 0; i < length; i++ )
  354.             sputc( &stream, getRandomByte() );
  355.         buffer[ 0 ] |= 0x80;    /* Make the random value as big as possible */
  356.         status = cryptInfoPtr->capabilityInfo->encryptFunction( cryptInfoPtr,
  357.                                                     buffer, CRYPT_UNUSED );
  358.         }
  359.     else
  360.         {
  361.         int keyOffset;
  362.  
  363.         /* Encode the payload using the format given in PKCS #1.  The format
  364.            for encrypted data is [ 0 ][ 2 ][ nonzero random padding ][ 0 ]
  365.            [ payload ] which is done by the following code.  Note that the
  366.            random padding is a nice place for a subliminal channel,
  367.            especially with large public key sizes where you can communicate
  368.            more information in the padding than in the payload */
  369.         sputc( &stream, 0 );
  370.         sputc( &stream, 2 );
  371.         for( i = 0; i < length - ( payloadSize + 3 ); i++ )
  372.             {
  373.             register int ch;    /* Try and keep it out of memory */
  374.  
  375.             /* Insert subliminal channel here */
  376.             while( ( ch = getRandomByte() ) == 0 );
  377.             sputc( &stream, ch );
  378.             }
  379.         sputc( &stream, 0 );
  380.         status = writeKeyInfo( &stream, sessionKeyInfoPtr, &keyOffset, FALSE );
  381.  
  382.         /* Write the key into the buffer and encrypt it */
  383.         if( cryptStatusOK( status ) )
  384.             {
  385.             /* Copy the key in at the last possible moment, then encrypt it */
  386.             memcpy( buffer + keyOffset, sessionKeyInfoPtr->userKey,
  387.                     sessionKeyInfoPtr->userKeyLength );
  388.             status = cryptInfoPtr->capabilityInfo->encryptFunction( cryptInfoPtr,
  389.                                                     buffer, CRYPT_UNUSED );
  390.             }
  391.         }
  392.  
  393.     /* Now write the encrypted key to the output stream */
  394.     if( cryptStatusOK( status ) )
  395.         {
  396.         STREAM outputStream;
  397.  
  398.         sMemOpen( &outputStream, encryptedKey, STREAMSIZE_UNKNOWN );
  399.         status = writePKCEncryptedKey( &outputStream, cryptInfoPtr,
  400.                                        sessionKeyInfoPtr, buffer, length );
  401.         *encryptedKeyLength = sMemSize( &outputStream );
  402.         sMemDisconnect( &outputStream );
  403.         }
  404.  
  405.     /* Clean up */
  406.     secureFree( ( void ** ) &buffer );
  407.     sMemClose( &stream );
  408.     return( status );
  409.     }
  410.  
  411. /* Import a conventional-encrypted session key.  This is seperated out from
  412.    the main cryptImportKey() code because the conventional and PKC export
  413.    code is completely different, even though it's called via the same API */
  414.  
  415. static int importConventionalKey( void *encryptedKey,
  416.                                   CRYPT_INFO *cryptInfoPtr,
  417.                                   CRYPT_CONTEXT *sessionKeyContext )
  418.     {
  419.     CRYPT_OBJECT_INFO cryptObjectInfo;
  420.     STREAM stream;
  421.     BYTE *buffer;
  422.     int status, keyInfoLength;
  423.  
  424.     /* Initialise various things */
  425.     if( ( status = secureMalloc( ( void ** ) &buffer, CRYPT_MAX_PKCSIZE ) ) != CRYPT_OK )
  426.         return( status );
  427.     sMemConnect( &stream, encryptedKey, STREAMSIZE_UNKNOWN );
  428.  
  429.     /* Read the encrypted key record up to the start of the encrypted key */
  430.     status = readEncryptedKey( &stream, cryptInfoPtr, &cryptObjectInfo,
  431.                                &keyInfoLength );
  432.     if( status == CRYPT_BADPARM )
  433.         /* Make the error code more specific if we're passed the wrong
  434.            encryption context to decrypt the key */
  435.         status = CRYPT_BADPARM2;
  436.  
  437.     /* Extract the encrypted key from the buffer and decrypt it */
  438.     if( !cryptStatusError( status ) && \
  439.         cryptStatusOK( status = loadIV( cryptInfoPtr, cryptObjectInfo.iv,
  440.                                         cryptObjectInfo.ivSize ) ) )
  441.         {
  442.         memcpy( buffer, ( BYTE * ) encryptedKey + sMemSize( &stream ),
  443.                 keyInfoLength );
  444.         status = cryptInfoPtr->capabilityInfo->decryptFunction( cryptInfoPtr,
  445.                                                     buffer, keyInfoLength );
  446.         }
  447.     sMemDisconnect( &stream );
  448.  
  449.     /* Create an encryption context loaded with keying information from the
  450.        decrypted buffer contents */
  451.     if( cryptStatusOK( status ) )
  452.         {
  453.         STREAM inputStream;
  454.  
  455.         sMemConnect( &inputStream, buffer, keyInfoLength );
  456.         status = readKeyInfo( &inputStream, sessionKeyContext );
  457.         if( !cryptStatusError( status ) )
  458.             status = CRYPT_OK;    /* The readXXX() functions return a byte count */
  459.         sMemClose( &inputStream );
  460.         }
  461.     secureFree( ( void ** ) &buffer );
  462.  
  463.     /* Set the control vector from the information in the EncryptedKey record
  464.        and make sure the key cookie matches the one generated from the key */
  465.     if( cryptStatusOK( status ) )
  466.         {
  467.         CRYPT_INFO *sessionKeyInfoPtr = CONTEXT_TO_INFO( *sessionKeyContext );
  468.  
  469.         sessionKeyInfoPtr->controlVector = cryptObjectInfo.controlVector;
  470.         if( cryptObjectInfo.cookieSize && \
  471.             memcmp( sessionKeyInfoPtr->keyCookie, cryptObjectInfo.cookie,
  472.                     KEY_COOKIE_SIZE ) )
  473.             status = CRYPT_WRONGKEY;
  474.         }
  475.  
  476.     return( status );
  477.     }
  478.  
  479. /* Import a PKC-encrypted session key */
  480.  
  481. CRET cryptImportKey( void CPTR encryptedKey,
  482.                      const CRYPT_CONTEXT cryptContext,
  483.                      CRYPT_CONTEXT CPTR sessionKeyContext )
  484.     {
  485.     CRYPT_INFO *cryptInfoPtr = CONTEXT_TO_INFO( cryptContext );
  486.     CRYPT_OBJECT_INFO cryptObjectInfo;
  487.     CRYPT_ALGO cryptAlgo;
  488.     STREAM stream;
  489.     BYTE *buffer;
  490.     int length, status;
  491.  
  492.     /* Perform basic error checking */
  493.     if( encryptedKey == NULL )
  494.         return( CRYPT_BADPARM1 );
  495.     if( isBadCookie( cryptContext ) || \
  496.         cryptInfoPtr->checkValue != CRYPT_MAGIC )
  497.         return( CRYPT_BADPARM2 );
  498.     if( sessionKeyContext == NULL )
  499.         return( CRYPT_BADPARM3 );
  500.     if( !cryptInfoPtr->keySet )
  501.         return( CRYPT_NOKEY );
  502.     if( cryptInfoPtr->capabilityInfo->encryptFunction == NULL )
  503.         return( CRYPT_NOALGO );
  504.  
  505.     /* If it's a conventional encryption context, import it as such */
  506.     if( !cryptInfoPtr->isPKCcontext )
  507.         return( importConventionalKey( encryptedKey, cryptInfoPtr,
  508.                                        sessionKeyContext ) );
  509.  
  510.     /* We can't decrypt with a public key */
  511.     if( cryptInfoPtr->isPublicKey )
  512.         return( CRYPT_BADPARM2 );
  513.  
  514.     /* Initialise various things */
  515.     if( ( status = secureMalloc( ( void ** ) &buffer, CRYPT_MAX_PKCSIZE ) ) != CRYPT_OK )
  516.         return( status );
  517.     cryptAlgo = cryptInfoPtr->capabilityInfo->cryptAlgo;
  518.     length = bitsToBytes( cryptInfoPtr->keySizeBits );
  519.     sMemConnect( &stream, encryptedKey, STREAMSIZE_UNKNOWN );
  520.  
  521.     /* Read the encrypted key record up to the start of the encrypted key */
  522.     status = readPKCEncryptedKey( &stream, cryptInfoPtr, sessionKeyContext,
  523.                                   &cryptObjectInfo );
  524.     if( cryptStatusError( status ) )
  525.         goto endImportKey;
  526.  
  527.     /* Extract the encrypted key from the buffer and decrypt it */
  528.     memcpy( buffer, ( BYTE * ) encryptedKey + sMemSize( &stream ), length );
  529.     status = cryptInfoPtr->capabilityInfo->decryptFunction( cryptInfoPtr,
  530.                                                     buffer, CRYPT_UNUSED );
  531.     if( cryptStatusError( status ) )
  532.         {
  533.         /* If it's a DH key object, the conventional encryption context will
  534.            already have been created so we need to delete it before we exit */
  535.         if( cryptAlgo == CRYPT_ALGO_DH )
  536.             cryptDestroyContext( *sessionKeyContext );
  537.         goto endImportKey;
  538.         }
  539.  
  540.     /* Diffie-Hellman and conventional PKC's are treated slightly differently
  541.        since DH can't embed information in the shared secret */
  542.     if( cryptAlgo == CRYPT_ALGO_DH )
  543.         {
  544.         CRYPT_INFO *sessionKeyInfoPtr = CONTEXT_TO_INFO( *sessionKeyContext );
  545.         CRYPT_QUERY_INFO cryptQueryInfo;
  546.         int keyLength;
  547.  
  548.         /* Find out how much of the shared secret we can use for the key */
  549.         cryptQueryContext( *sessionKeyContext, &cryptQueryInfo );
  550.         keyLength = min( length, cryptQueryInfo.maxKeySize );
  551.         zeroise( &cryptQueryInfo, sizeof( CRYPT_QUERY_INFO ) );
  552.  
  553.         /* Make sure the shared secret is cleared as soon as possible */
  554.         sessionKeyInfoPtr->clearBuffer = TRUE;
  555.  
  556.         /* Diffie-Hellman merely establishes a shared secret (the crypt
  557.            context creation is done from the information stored in the
  558.            encrypted key record), so all that's left to do is to load the key
  559.            into the encryption context from the least-significant bytes of
  560.            the shared secret */
  561.         status = cryptLoadContext( *sessionKeyContext,
  562.                                    buffer + length - keyLength, keyLength );
  563.         if( cryptStatusError( status ) )
  564.             cryptDestroyContext( *sessionKeyContext );
  565.         sessionKeyInfoPtr->clearBuffer = FALSE;
  566.         }
  567.     else
  568.         {
  569.         STREAM inputStream;
  570.         int ch, i;
  571.  
  572.         /* Undo the PKCS #1 padding.  The PKCS format for encrypted data is
  573.            [ 0 ][ 2 ][ random nonzero padding ][ 0 ][ payload ] which is
  574.            checked for by the following code */
  575.         sMemConnect( &inputStream, buffer, length );
  576.         if( sgetc( &inputStream ) != 0 || sgetc( &inputStream ) != 2 )
  577.             {
  578.             status = CRYPT_BADDATA;
  579.             goto endImportPKCKey;
  580.             }
  581.         for( i = 0; i < length - 3; i++ )
  582.             if( ( ch = sgetc( &inputStream ) ) == 0 )
  583.                 break;
  584.         if( ch != 0 )
  585.             {
  586.             status = CRYPT_BADDATA;
  587.             goto endImportPKCKey;
  588.             }
  589.  
  590.         /* Create an encryption context loaded with keying information from
  591.            the decrypted buffer contents */
  592.         status = readKeyInfo( &inputStream, sessionKeyContext );
  593.         if( !cryptStatusError( status ) )
  594.             status = CRYPT_OK;    /* The readXXX() functions return a byte count */
  595. endImportPKCKey:
  596.         sMemClose( &inputStream );
  597.         }
  598.  
  599.     /* Set the control vector from the information in the PKCEncryptedKey
  600.        record and make sure the key cookie matches the one generated from the
  601.        key */
  602.     if( cryptStatusOK( status ) )
  603.         {
  604.         CRYPT_INFO *sessionKeyInfoPtr = CONTEXT_TO_INFO( *sessionKeyContext );
  605.  
  606.         sessionKeyInfoPtr = CONTEXT_TO_INFO( *sessionKeyContext );
  607.         sessionKeyInfoPtr->controlVector = cryptObjectInfo.controlVector;
  608.         if( cryptAlgo != CRYPT_ALGO_DH && cryptObjectInfo.cookieSize && \
  609.             memcmp( sessionKeyInfoPtr->keyCookie, cryptObjectInfo.cookie,
  610.                     KEY_COOKIE_SIZE ) )
  611.             status = CRYPT_WRONGKEY;
  612.         }
  613.  
  614.     /* Clean up */
  615. endImportKey:
  616.     secureFree( ( void ** ) &buffer );
  617.     sMemDisconnect( &stream );
  618.     return( status );
  619.     }
  620.