home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / crypl200.zip / KEYMGMT / ASN1OBJS.C < prev    next >
Text File  |  1996-10-11  |  55KB  |  1,594 lines

  1. /****************************************************************************
  2. *                                                                            *
  3. *                         ASN.1 Object Management Routines                    *
  4. *                        Copyright Peter Gutmann 1992-1996                    *
  5. *                                                                            *
  6. ****************************************************************************/
  7.  
  8. #include <ctype.h>
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #if defined( INC_ALL ) || defined( INC_CHILD )
  13.   #include "asn1.h"
  14.   #include "asn1objs.h"
  15. #else
  16.   #include "keymgmt/asn1.h"
  17.   #include "keymgmt/asn1objs.h"
  18. #endif /* Compiler-specific includes */
  19.  
  20. /****************************************************************************
  21. *                                                                            *
  22. *                                Utility Routines                            *
  23. *                                                                            *
  24. ****************************************************************************/
  25.  
  26. /* Context-specific tag for the message digest information record */
  27.  
  28. enum { CTAG_MD_ALGOINFO };
  29.  
  30. /* Context-specific tag for the key information record */
  31.  
  32. enum { CTAG_KI_ALGOINFO };
  33.  
  34. /* Context-specific tags for the conventional-encrypted key record */
  35.  
  36. enum { CTAG_CK_ALGOINFO, CTAG_CK_DERIVATIONINFO, CTAG_CK_KEYCOOKIE,
  37.        CTAG_CK_CONTROLVECTOR, CTAG_CK_IV };
  38.  
  39. /* Context-specific tags for the PKC-encrypted key record */
  40.  
  41. enum { CTAG_PK_ALGOINFO, CTAG_PK_KEYCOOKIE, CTAG_PK_CONTROLVECTOR };
  42.  
  43. /* Context-specific tag for the signature record */
  44.  
  45. enum { CTAG_SG_ALGOINFO, CTAG_SG_SIGNATURECOOKIE };
  46.  
  47. /* Context-specific tag for the encrypted data record */
  48.  
  49. enum { CTAG_ED_KEYCOOKIE };
  50.  
  51. /* Context-specific tag for the signed data record */
  52.  
  53. enum { CTAG_SD_SIGNATURECOOKIE };
  54.  
  55. /* Evaluate the size of the algorithm-specific parameters field (the
  56.    constant 2 defines the size of the tag and the length field) */
  57.  
  58. static int sizeofAlgorithmParams( const CRYPT_INFO *cryptInfo )
  59.     {
  60.     BOOLEAN boolean;
  61.     long integer;
  62.  
  63.     switch( cryptInfo->capabilityInfo->cryptAlgo )
  64.         {
  65.         case CRYPT_ALGO_DES:
  66.         case CRYPT_ALGO_3DES:
  67.             return( sizeofBoolean() + 2 );
  68.  
  69.         case CRYPT_ALGO_MDCSHS:
  70.             integer = getMDCSHSinfo( cryptInfo );
  71.             return( sizeofShortInteger( integer ) + 2 );
  72.  
  73. #ifndef NO_PATENT
  74.         case CRYPT_ALGO_RC5:
  75.             integer = getRC5info( cryptInfo );
  76.             return( sizeofShortInteger( integer ) + 2 );
  77. #endif /* NO_PATENT */
  78.  
  79.         case CRYPT_ALGO_SAFER:
  80.             integer = getSaferInfo( cryptInfo, &boolean );
  81.             return( sizeofBoolean() + sizeofShortInteger( integer ) + 2 );
  82.  
  83.         case CRYPT_ALGO_BLOWFISH:
  84.             integer = getBlowfishInfo( cryptInfo, &boolean );
  85.             return( sizeofBoolean() + sizeofShortInteger( integer ) + 2 );
  86.         }
  87.  
  88.     return( CRYPT_ERROR );    /* Internal error, should never happen */
  89.     }
  90.  
  91. /* Write the parameters for a conventional encryption algorithm */
  92.  
  93. static void writeAlgorithmParams( STREAM *stream,
  94.                                   const CAPABILITY_INFO *capabilityInfo,
  95.                                   const CRYPT_INFO *cryptInfo )
  96.     {
  97.     /* It's a composite type.  First, write the algorithm ID fields */
  98.     writeEnumerated( stream, capabilityInfo->cryptAlgo, DEFAULT_TAG );
  99.     writeEnumerated( stream, capabilityInfo->cryptMode, DEFAULT_TAG );
  100.  
  101.     /* Now write any algorithm-specific fields.  We've already checked
  102.        above for unknown algorithms so we don't need to include a default
  103.        case for this here */
  104.     if( !cryptInfo->privateUseDefaults )
  105.         {
  106.         BOOLEAN boolean;
  107.         long integer;
  108.  
  109.         writeCtag( stream, CTAG_KI_ALGOINFO, TRUE );
  110.         switch( capabilityInfo->cryptAlgo )
  111.             {
  112.             case CRYPT_ALGO_DES:
  113.                 boolean = getDESinfo( cryptInfo );
  114.                 writeLength( stream, sizeofBoolean() );
  115.                 writeBoolean( stream, boolean, DEFAULT_TAG );
  116.                 break;
  117.  
  118.             case CRYPT_ALGO_3DES:
  119.                 boolean = get3DESinfo( cryptInfo );
  120.                 writeLength( stream, sizeofBoolean() );
  121.                 writeBoolean( stream, boolean, DEFAULT_TAG );
  122.                 break;
  123.  
  124.             case CRYPT_ALGO_MDCSHS:
  125.                 integer = getMDCSHSinfo( cryptInfo );
  126.                 writeLength( stream, sizeofShortInteger( integer ) );
  127.                 writeShortInteger( stream, integer, DEFAULT_TAG );
  128.                 break;
  129.  
  130. #ifndef NO_PATENT
  131.             case CRYPT_ALGO_RC5:
  132.                 integer = getRC5info( cryptInfo );
  133.                 writeLength( stream, sizeofShortInteger( integer ) );
  134.                 writeShortInteger( stream, integer, DEFAULT_TAG );
  135.                 break;
  136. #endif /* NO_PATENT */
  137.  
  138.             case CRYPT_ALGO_SAFER:
  139.                 integer = getSaferInfo( cryptInfo, &boolean );
  140.                 writeLength( stream, sizeofBoolean() +
  141.                              sizeofShortInteger( integer ) );
  142.                 writeBoolean( stream, boolean, DEFAULT_TAG );
  143.                 writeShortInteger( stream, integer, DEFAULT_TAG );
  144.                 break;
  145.  
  146.             case CRYPT_ALGO_BLOWFISH:
  147.                 integer = getBlowfishInfo( cryptInfo, &boolean );
  148.                 writeLength( stream, sizeofBoolean() +
  149.                              sizeofShortInteger( integer ) );
  150.                 writeBoolean( stream, boolean, DEFAULT_TAG );
  151.                 writeShortInteger( stream, integer, DEFAULT_TAG );
  152.                 break;
  153.             }
  154.         }
  155.     }
  156.  
  157. /* Read the parameters for a conventional encryption algorithm and either
  158.    read them into a CRYPT_OBJECT_INFO structure or create an encryption
  159.    context to hold them */
  160.  
  161. static int readAlgorithmParams( STREAM *stream, CRYPT_CONTEXT *cryptContext,
  162.                                 CRYPT_OBJECT_INFO *cryptObjectInfo )
  163.     {
  164.     CRYPT_ALGO cryptAlgo;
  165.     CRYPT_MODE cryptMode;
  166.     CRYPT_INFO *cryptInfo;
  167.     int readDataLength, tagLength, status;
  168.  
  169.     /* Read the encryption algorithm and type and make sure we know what to
  170.        do with it */
  171.     readDataLength = readEnumerated( stream, ( int * ) &cryptAlgo );
  172.     readDataLength += readEnumerated( stream, ( int * ) &cryptMode );
  173.     if( cryptObjectInfo != NULL )
  174.         {
  175.         cryptObjectInfo->cryptAlgo = cryptAlgo;
  176.         cryptObjectInfo->cryptMode = cryptMode;
  177.         }
  178.     if( cryptStatusError( status = cryptModeAvailable( cryptAlgo, cryptMode ) ) )
  179.         return( status );
  180.  
  181.     /* Create an encryption context to hold the encrypted data information if
  182.        required */
  183.     if( cryptContext != NULL )
  184.         {
  185.         if( cryptStatusError( status = cryptCreateContext( cryptContext,
  186.                                                 cryptAlgo, cryptMode ) ) )
  187.             return( status );
  188.         cryptInfo = CONTEXT_TO_INFO( *cryptContext );
  189.         }
  190.  
  191.     /* Read the algorithm-specific parameters if necessary */
  192.     tagLength = checkReadCtag( stream, CTAG_KI_ALGOINFO, TRUE );
  193.     if( tagLength )
  194.         {
  195.         long length, integer;
  196.         BOOLEAN boolean;
  197.         void *cPtr;
  198.  
  199.         /* Set up a pointer to the extended parameters area if necessary (we
  200.            can reuse the keyID memory because it's only used for PKC's) */
  201.         if( cryptObjectInfo != NULL )
  202.             {
  203.             cryptObjectInfo->cryptContextExInfo = cryptObjectInfo->keyID;
  204.             cPtr = cryptObjectInfo->cryptContextExInfo;
  205.             }
  206.  
  207.         readLength( stream, &length );
  208.         readDataLength += ( int ) length + tagLength;
  209.         switch( cryptAlgo )
  210.             {
  211.             case CRYPT_ALGO_DES:
  212.                 readBoolean( stream, &boolean );
  213.                 if( cryptContext == NULL )
  214.                     ( ( CRYPT_INFO_DES * ) cPtr )->isDESX = boolean;
  215.                 else
  216.                     setDESinfo( cryptInfo, boolean );
  217.                 break;
  218.  
  219.             case CRYPT_ALGO_3DES:
  220.                 readBoolean( stream, &boolean );
  221.                 if( cryptContext == NULL )
  222.                     ( ( CRYPT_INFO_3DES * ) cPtr )->isThreeKey = boolean;
  223.                 else
  224.                     set3DESinfo( cryptInfo, boolean );
  225.                 break;
  226.  
  227.             case CRYPT_ALGO_MDCSHS:
  228.                 readShortInteger( stream, &integer );
  229.                 if( cryptContext == NULL )
  230.                     ( ( CRYPT_INFO_MDCSHS * ) cPtr )->keySetupIterations = \
  231.                                                             ( int ) integer;
  232.                 else
  233.                     setMDCSHSinfo( cryptInfo, ( int ) integer );
  234.                 break;
  235.  
  236. #ifndef NO_PATENT
  237.             case CRYPT_ALGO_RC5:
  238.                 readShortInteger( stream, &integer );
  239.                 if( cryptContext == NULL )
  240.                     ( ( CRYPT_INFO_RC5 * ) cPtr )->rounds = ( int ) integer;
  241.                 else
  242.                     setRC5info( cryptInfo, ( int ) integer );
  243.                 break;
  244. #endif /* NO_PATENT */
  245.  
  246.             case CRYPT_ALGO_SAFER:
  247.                 readBoolean( stream, &boolean );
  248.                 readShortInteger( stream, &integer );
  249.                 if( cryptContext == NULL )
  250.                     {
  251.                     ( ( CRYPT_INFO_SAFER * ) cPtr )->useSaferSK = boolean;
  252.                     ( ( CRYPT_INFO_SAFER * ) cPtr )->rounds = ( int ) integer;
  253.                     }
  254.                 else
  255.                     setSaferInfo( cryptInfo, boolean, ( int ) integer );
  256.                 break;
  257.  
  258.             case CRYPT_ALGO_BLOWFISH:
  259.                 readBoolean( stream, &boolean );
  260.                 readShortInteger( stream, &integer );
  261.                 if( cryptContext == NULL )
  262.                     {
  263.                     ( ( CRYPT_INFO_BLOWFISH * ) cPtr )->useBlowfishSK = boolean;
  264.                     ( ( CRYPT_INFO_BLOWFISH * ) cPtr )->keySetupIterations = \
  265.                                                             ( int ) integer;
  266.                     }
  267.                 else
  268.                     setBlowfishInfo( cryptInfo, boolean, ( int ) integer );
  269.                 break;
  270.  
  271.             default:
  272.                 if( cryptContext != NULL )
  273.                     cryptDestroyContext( *cryptContext );
  274.                 return( CRYPT_NOALGO );
  275.             }
  276.         }
  277.     else
  278.         /* No algorithm-specific parameters, use default settings */
  279.         if( cryptObjectInfo != NULL )
  280.             cryptObjectInfo->cryptContextExInfo = ( void * ) CRYPT_UNUSED;
  281.  
  282.     return( readDataLength );
  283.     }
  284.  
  285. /* Read a generic cookie */
  286.  
  287. static int readCookie( STREAM *stream, BYTE *cookie, int *cookieSize,
  288.                        const int expectedSize )
  289.     {
  290.     BYTE buffer[ MAX_COOKIE_SIZE ];
  291.     int readDataLength, length;
  292.  
  293.     readDataLength = readStaticOctetStringData( stream, buffer, &length,
  294.                                                 expectedSize );
  295.     if( ( readDataLength <= 0 ) || ( length != expectedSize ) )
  296.         {
  297.         sSetError( stream, STREAM_BADDATA );
  298.         return( CRYPT_BADDATA );
  299.         }
  300.     memcpy( cookie, buffer, expectedSize );
  301.     *cookieSize = expectedSize;
  302.  
  303.     return( readDataLength );
  304.     }
  305.  
  306. /* Write/read the key cookie and control vector */
  307.  
  308. static void writeKeyParams( STREAM *stream, const BYTE *keyCookie,
  309.                             const int cookieTag, const long controlVector,
  310.                             const int vectorTag )
  311.     {
  312.     if( keyCookie != NULL )
  313.         writeByteString( stream, keyCookie, KEY_COOKIE_SIZE, cookieTag );
  314.     if( controlVector )
  315.         writeBitString( stream, controlVector, vectorTag );
  316.     }
  317.  
  318. static int readKeyParams( STREAM *stream, BYTE *keyCookie, int *cookieSize,
  319.                           const int cookieTag, long *controlVector,
  320.                           const int vectorTag )
  321.     {
  322.     int readDataLength = 0, tagLength;
  323.  
  324.     /* Read the key cookie if necessary */
  325.     *cookieSize = 0;
  326.     tagLength = checkReadCtag( stream, cookieTag, FALSE );
  327.     if( tagLength )
  328.         readDataLength += readCookie( stream, keyCookie, cookieSize,
  329.                                       KEY_COOKIE_SIZE ) + tagLength;
  330.  
  331.     /* Read the control vector if necessary */
  332.     tagLength = checkReadCtag( stream, vectorTag, FALSE );
  333.     if( tagLength )
  334.         readDataLength += readBitStringData( stream, controlVector ) + tagLength;
  335.  
  336.     return( readDataLength );
  337.     }
  338.  
  339. /* Read the outer wrapper and start of a cryptlib object */
  340.  
  341. int readObjectWrapper( STREAM *stream, CRYPT_OBJECT_TYPE *objectType,
  342.                        long *length )
  343.     {
  344.     static struct { int tag; CRYPT_OBJECT_TYPE objectType; } tagType[] = {
  345.         { BER_ENCRYPTED_KEY, CRYPT_OBJECT_ENCRYPTED_KEY },
  346.         { BER_PKCENCRYPTED_KEY, CRYPT_OBJECT_PKCENCRYPTED_KEY },
  347.         { BER_SIGNATURE, CRYPT_OBJECT_SIGNATURE },
  348.         { BER_ENCRYPTED_DATA, CRYPT_OBJECT_ENCRYPTED_DATA },
  349.         { BER_COMPRESSED_DATA, CRYPT_OBJECT_COMPRESSED_DATA },
  350.         { BER_SIGNED_DATA, CRYPT_OBJECT_SIGNED_DATA },
  351.         { BER_RAW_DATA, CRYPT_OBJECT_RAW_DATA },
  352.         { BER_NONDATA, CRYPT_OBJECT_NONDATA },
  353.         { 0, 0 } };
  354.     int readDataLength, tag, i;
  355.     long dummy;
  356.  
  357.     /* Read the outer wrapper identifier and length fields */
  358.     tag = readTag( stream );
  359.     for( i = 0; tagType[ i ].tag; i++ )
  360.         if( tagType[ i ].tag == tag )
  361.             break;
  362.     if( tagType[ i ].tag )
  363.         *objectType = tagType[ i ].objectType;
  364.     else
  365.         {
  366.         *objectType = CRYPT_OBJECT_NONE;
  367.         sSetError( stream, STREAM_BADDATA );
  368.         }
  369.     readDataLength = readLength( stream, length ) + 1;
  370.     *length += readDataLength;    /* Include size of tag in total length */
  371.  
  372.     /* Read the identifier and length fields */
  373.     if( readTag( stream ) != BER_SEQUENCE || *objectType == CRYPT_ERROR )
  374.         {
  375.         sSetError( stream, STREAM_BADDATA );
  376.         return( CRYPT_BADDATA );
  377.         }
  378.     readDataLength += readLength( stream, &dummy ) + 1;
  379.  
  380.     if( sGetStatus( stream ) != STREAM_OK )
  381.         return( CRYPT_BADDATA );
  382.     return( readDataLength );
  383.     }
  384.  
  385. /* Read the start of a conventionally encrypted key object */
  386.  
  387. int readCKObject( STREAM *stream, CRYPT_OBJECT_INFO *cryptObjectInfo )
  388.     {
  389.     int readDataLength, tagLength;
  390.  
  391.     /* Read the algorithm parameters */
  392.     readDataLength = readAlgorithmParams( stream, NULL, cryptObjectInfo );
  393.     if( cryptStatusError( readDataLength ) )
  394.         return( readDataLength );
  395.  
  396.     /* Read the key derivation information */
  397.     tagLength = checkReadCtag( stream, CTAG_CK_DERIVATIONINFO, TRUE );
  398.     if( tagLength )
  399.         {
  400.         long integer, length;
  401.  
  402.         readLength( stream, &length );
  403.         readDataLength = ( int ) length + tagLength;
  404.         readEnumerated( stream, ( int * ) &cryptObjectInfo->keySetupAlgo );
  405.         readShortInteger( stream, &integer );
  406.         cryptObjectInfo->keySetupIterations = ( int ) integer;
  407.         }
  408.     else
  409.         {
  410.         /* Use the default settings if none are given */
  411.         cryptObjectInfo->keySetupAlgo = DEFAULT_KEYSETUP_ALGO;
  412.         cryptObjectInfo->keySetupIterations = DEFAULT_KEYSETUP_ITERATIONS;
  413.         }
  414.  
  415.     /* Read the key cookie and control vector */
  416.     readDataLength += readKeyParams( stream, cryptObjectInfo->cookie,
  417.                                      &cryptObjectInfo->cookieSize,
  418.                                      CTAG_CK_KEYCOOKIE,
  419.                                      &cryptObjectInfo->controlVector,
  420.                                      CTAG_CK_CONTROLVECTOR );
  421.  
  422.     if( sGetStatus( stream ) != STREAM_OK )
  423.         return( CRYPT_BADDATA );
  424.     return( readDataLength );
  425.     }
  426.  
  427. /* Read the start of a public-key encrypted key or signed object */
  428.  
  429. int readPKObject( STREAM *stream, BYTE *keyID, int *keyIDsize,
  430.                   CRYPT_ALGO *cryptAlgo )
  431.     {
  432.     int readDataLength, status;
  433.  
  434.     /* Read the key ID */
  435.     readDataLength = readRawObject( stream, keyID, keyIDsize,
  436.                                     CRYPT_MAX_KEYIDSIZE, BER_SEQUENCE );
  437.     if( cryptStatusError( readDataLength ) )
  438.         return( CRYPT_BADDATA );
  439.     *keyIDsize += sizeof( BYTE ) + sizeof( BYTE );    /* Add header size */
  440.  
  441.     /* Read the PKC algorithm type and make sure we can handle it */
  442.     readDataLength += readEnumerated( stream, ( int * ) cryptAlgo );
  443.     if( cryptStatusError( status = cryptAlgoAvailable( *cryptAlgo ) ) )
  444.         return( status );
  445.  
  446.     if( sGetStatus( stream ) != STREAM_OK )
  447.         return( CRYPT_BADDATA );
  448.     return( readDataLength );
  449.     }
  450.  
  451. /* Read more of a public-key encrypted PKObject */
  452.  
  453. int readPKKeyObject( STREAM *stream, CRYPT_ALGO cryptAlgo,
  454.                      CRYPT_CONTEXT *cryptContext,
  455.                      CRYPT_OBJECT_INFO *cryptObjectInfo )
  456.     {
  457.     int readDataLength = 0, tagLength;
  458.     long length;
  459.  
  460.     /* Make sure we generate an error if we don't load a context */
  461.     if( cryptContext != NULL )
  462.         *cryptContext = NULL;
  463.  
  464.     /* Skip any optional algorithm-specific information */
  465.     tagLength = checkReadCtag( stream, CTAG_PK_ALGOINFO, TRUE );
  466.     if( tagLength )
  467.         {
  468.         int status;
  469.  
  470.         readLength( stream, &length );
  471.         readDataLength = ( int ) length + tagLength;
  472.         if( cryptContext == NULL )
  473.             sSkip( stream, ( int ) length );
  474.         else
  475.             switch( cryptAlgo )
  476.                 {
  477.                 case CRYPT_ALGO_DH:
  478.                     /* Read the encryption algorithm information and create
  479.                        an encryption context from it */
  480.                     if( cryptStatusError( status = \
  481.                             readAlgorithmParams( stream, cryptContext, NULL ) ) )
  482.                         return( status );
  483.                     break;
  484.  
  485.                 default:
  486.                     return( CRYPT_NOALGO );
  487.                 }
  488.         }
  489.     else
  490.         /* No algorithm-specific parameters, use default settings */
  491.         if( cryptObjectInfo != NULL )
  492.             cryptObjectInfo->cryptContextExInfo = ( void * ) CRYPT_UNUSED;
  493.  
  494.     /* Read the key cookie and control vector */
  495.     readDataLength += readKeyParams( stream, cryptObjectInfo->cookie,
  496.                                      &cryptObjectInfo->cookieSize,
  497.                                      CTAG_PK_KEYCOOKIE,
  498.                                      &cryptObjectInfo->controlVector,
  499.                                      CTAG_PK_CONTROLVECTOR );
  500.  
  501.     if( sGetStatus( stream ) != STREAM_OK )
  502.         return( CRYPT_BADDATA );
  503.     return( readDataLength );
  504.     }
  505.  
  506. /* Generate a key cookie */
  507.  
  508. int generateKeyCookie( CRYPT_INFO *cryptInfo )
  509.     {
  510.     STREAM stream;
  511.     BYTE *buffer;
  512.     int dataLength, status = CRYPT_OK;
  513.  
  514.     /* Allocate a buffer for the DER-encoded key parameters and write
  515.        everything but the key to it */
  516.     if( ( buffer = ( BYTE * ) malloc( CRYPT_MAX_PKCSIZE ) ) == NULL )
  517.         return( CRYPT_NOMEM );
  518.     sMemOpen( &stream, buffer, CRYPT_MAX_PKCSIZE );
  519.     status = writeKeyInfo( &stream, cryptInfo, &dataLength, FALSE );
  520.     if( cryptStatusOK( status ) )
  521.         {
  522.         CRYPT_CONTEXT cryptContext;
  523.  
  524.         /* Hash the algorithm parameters and key and copy the first
  525.            KEY_COOKIE_SIZE bytes to the key cookie.  Since we're dealing with
  526.            sensitive keying material here, we need to use the external hash
  527.            API rather than the internal one to make sure the memory
  528.            containing the key is protected */
  529.         status = cryptCreateContext( &cryptContext, CRYPT_ALGO_SHA, CRYPT_MODE_NONE );
  530.         if( cryptStatusOK( status ) )
  531.             {
  532.             CRYPT_QUERY_INFO cryptQueryInfo;
  533.  
  534.             cryptEncrypt( cryptContext, buffer, dataLength );
  535.             cryptEncrypt( cryptContext, cryptInfo->userKey, cryptInfo->userKeyLength );
  536.             cryptEncrypt( cryptContext, buffer, 0 );
  537.             cryptQueryContext( cryptContext, &cryptQueryInfo );
  538.             cryptDestroyContext( cryptContext );
  539.             memcpy( cryptInfo->keyCookie, cryptQueryInfo.hashValue, KEY_COOKIE_SIZE );
  540.             zeroise( &cryptQueryInfo, sizeof( CRYPT_QUERY_INFO ) );
  541.             }
  542.         }
  543.  
  544.     /* Clean up */
  545.     sMemClose( &stream );
  546.     free( buffer );
  547.     return( status );
  548.     }
  549.  
  550. /* Wrap an ASN.1 data type up inside an explicitly tagged type (this
  551.    converts, for example, a SEQUENCE into an [APPLICATION 0] SEQUENCE).
  552.    The extraLength parameter is provided for incomplete types where further
  553.    data will be added by the caller later on.
  554.  
  555.    This function is somewhat nasty in that it uses direct access to the
  556.    streams buffer to save complex byte-by-byte copying, which means we have to
  557.    be careful about what sort of stream we're working with */
  558.  
  559. static void wrapExplicitTag( STREAM *stream, int tag, long extraLength )
  560.     {
  561.     STREAM tagStream;
  562.     BYTE tagBuffer[ 10 ];
  563.     int length = sMemSize( stream ), tagLength;
  564.  
  565.     /* Write the explicit tag to a temporary stream */
  566.     sMemOpen( &tagStream, tagBuffer, 10 );
  567.     writeTag( &tagStream, tag );
  568.     writeLength( &tagStream, length + extraLength );
  569.     tagLength = sMemSize( &tagStream );
  570.  
  571.     /* Make sure there's enough room to add the new tag to the output */
  572.     if( stream->isNull )
  573.         stream->bufPos = tagLength + length;
  574.     else
  575.         if( stream->bufSize != STREAMSIZE_UNKNOWN && \
  576.             tagLength + length > stream->bufSize )
  577.             stream->status = STREAM_FULL;
  578.         else
  579.             {
  580.             /* Make room for the new tag and prepend it to the data */
  581.             memmove( stream->buffer + tagLength, stream->buffer, length );
  582.             memcpy( stream->buffer, tagStream.buffer, tagLength );
  583.             stream->bufPos = stream->bufEnd = tagLength + length;
  584.             }
  585.     sMemClose( &tagStream );
  586.     }
  587.  
  588. /****************************************************************************
  589. *                                                                            *
  590. *                            Message Digest Routines                            *
  591. *                                                                            *
  592. ****************************************************************************/
  593.  
  594. /* Write/read the message digest algorithm and optional parameters */
  595.  
  596. static int sizeofMessageDigestParams( const CRYPT_ALGO algorithm,
  597.                                       const int parameter,
  598.                                       const int extraLength )
  599.     {
  600.     int size;
  601.  
  602.     /* Evaluate the size of the enumerated value needed to encode the MD
  603.        algorithm type and any optional algorithm-specific information */
  604.     size = sizeofEnumerated( algorithm );
  605.     if( algorithm == CRYPT_ALGO_SHA && parameter )
  606.         /* The parameter is written as a SEQUENCE with a single BOOLEAN
  607.            field */
  608.         size += 2 + sizeofBoolean();
  609.     return( size + extraLength );
  610.     }
  611.  
  612. static void writeMessageDigestParams( STREAM *stream, const CRYPT_ALGO algorithm,
  613.                                       const int parameter, const int extraLength,
  614.                                       const int tag )
  615.     {
  616.     /* Write the identifier and length fields */
  617.     if( tag == DEFAULT_TAG )
  618.         writeTag( stream, BER_SEQUENCE );
  619.     else
  620.         writeCtag( stream, tag, TRUE );
  621.     writeLength( stream, sizeofMessageDigestParams( algorithm, parameter,
  622.                                                     extraLength ) );
  623.  
  624.     /* It's a composite type.  First write the enumeration which encodes the
  625.        MD type */
  626.     writeEnumerated( stream, algorithm, DEFAULT_TAG );
  627.  
  628.     /* Now write any algorithm-specific fields */
  629.     if( parameter )
  630.         {
  631.         writeCtag( stream, CTAG_MD_ALGOINFO, TRUE );
  632.         switch( algorithm )
  633.             {
  634.             case CRYPT_ALGO_SHA:
  635.                 writeLength( stream, sizeofBoolean() );
  636.                 writeBoolean( stream, ( BOOLEAN ) parameter, DEFAULT_TAG );
  637.                 break;
  638.             }
  639.         }
  640.     }
  641.  
  642. static int readMessageDigestParams( STREAM *stream, CRYPT_ALGO *algorithm,
  643.                                     int *parameter, const BOOLEAN readIdent )
  644.     {
  645.     int readDataLength = 0, tagLength;
  646.     long dummy;
  647.  
  648.     /* Read the identifier field if necessary */
  649.     if( readIdent )
  650.         {
  651.         if( readTag( stream ) != BER_SEQUENCE )
  652.             {
  653.             sSetError( stream, STREAM_BADDATA );
  654.             return( CRYPT_BADDATA );
  655.             }
  656.         readDataLength++;
  657.         }
  658.  
  659.     /* Read the algorithm type */
  660.     readDataLength += readLength( stream, &dummy );    /* Skip SEQUENCE length info */
  661.     readDataLength += readEnumerated( stream, ( int * ) algorithm );
  662.     *parameter = 0;        /* Most algorithms have no parameters */
  663.  
  664.     /* Read the algorithm-specific parameters if necessary */
  665.     tagLength = checkReadCtag( stream, CTAG_MD_ALGOINFO, TRUE );
  666.     if( tagLength )
  667.         {
  668.         long length;
  669.  
  670.         readLength( stream, &length );
  671.         readDataLength += ( int ) length + tagLength;
  672.         switch( *algorithm )
  673.             {
  674.             case CRYPT_ALGO_SHA:
  675.                 readBoolean( stream, ( BOOLEAN * ) parameter );
  676.                 break;
  677.  
  678.             default:
  679.                 return( CRYPT_NOALGO );
  680.             }
  681.         }
  682.  
  683.     return( readDataLength );
  684.     }
  685.  
  686. /* Initialise a message digest to a given value, and destroy it afterwards */
  687.  
  688. int newMessageDigest( MESSAGE_DIGEST *messageDigest, const CRYPT_ALGO mdAlgo,
  689.                       const BYTE *md, const int length )
  690.     {
  691.     /* Set up MD information */
  692.     memset( messageDigest, 0, sizeof( MESSAGE_DIGEST ) );
  693.     messageDigest->type = mdAlgo;
  694.     messageDigest->length = length;
  695.     if( length )
  696.         memcpy( messageDigest->data, md, length );
  697.  
  698.     return( CRYPT_OK );
  699.     }
  700.  
  701. int deleteMessageDigest( MESSAGE_DIGEST *messageDigest )
  702.     {
  703.     /* Zero the message digest fields */
  704.     return( newMessageDigest( messageDigest, CRYPT_ALGO_NONE, NULL, 0 ) );
  705.     }
  706.  
  707. /* Determine the encoded size of a message digest value */
  708.  
  709. int sizeofMessageDigest( const MESSAGE_DIGEST *messageDigest )
  710.     {
  711.     int size;
  712.  
  713.     /* It's a composite type.  Evaluate the size of the algorithm parameters
  714.        and the octet string needed to encode the MD itself */
  715.     size = sizeofMessageDigestParams( messageDigest->type,
  716.            messageDigest->isSHA, ( int ) sizeofObject( messageDigest->length ) );
  717.     return( sizeof( BYTE ) + calculateLengthSize( size ) + size );
  718.     }
  719.  
  720. /* Write a message digest value */
  721.  
  722. int writeMessageDigest( STREAM *stream, const MESSAGE_DIGEST *messageDigest,
  723.                         const int tag )
  724.     {
  725.     /* Write the header and algorithm information fields */
  726.     writeMessageDigestParams( stream, messageDigest->type,
  727.             messageDigest->isSHA, ( int ) sizeofObject( messageDigest->length ),
  728.             tag );
  729.  
  730.     /* Finally write the data as an octet string */
  731.     writeByteString( stream, messageDigest->data, messageDigest->length,
  732.                      DEFAULT_TAG );
  733.  
  734.     return( sGetStatus( stream ) );
  735.     }
  736.  
  737. /* Read a message digest value */
  738.  
  739. int _readMessageDigest( STREAM *stream, MESSAGE_DIGEST *messageDigest,
  740.                         const BOOLEAN readIdent )
  741.     {
  742.     int readDataLength = 0;
  743.  
  744.     /* Read the message digest algorithm information and optional parameters */
  745.     readDataLength = readMessageDigestParams( stream, &messageDigest->type,
  746.                                               ( int * ) &messageDigest->isSHA,
  747.                                               readIdent );
  748.     if( cryptStatusError( readDataLength ) )
  749.         return( readDataLength );
  750.  
  751.     /* Finally, read the digest itself */
  752.     readDataLength += readStaticOctetString( stream, messageDigest->data,
  753.                                              &messageDigest->length,
  754.                                              CRYPT_MAX_HASHSIZE );
  755.  
  756.     if( sGetStatus( stream ) != STREAM_OK )
  757.         return( CRYPT_BADDATA );
  758.     return( readDataLength );
  759.     }
  760.  
  761. /****************************************************************************
  762. *                                                                            *
  763. *                            Key Information Routines                        *
  764. *                                                                            *
  765. ****************************************************************************/
  766.  
  767. /* Determine the encoded size of a key information record */
  768.  
  769. int sizeofKeyInfo( const CRYPT_INFO *cryptInfo, const BOOLEAN addPadding )
  770.     {
  771.     int size;
  772.  
  773.     /* It's a composite type.  Evaluate the size of the enumerated value
  774.        needed to encode the algorithm type and mode, the size of the
  775.        encoded extra information, and the octet string needed to encode the
  776.        key */
  777.     size = sizeofEnumerated( cryptInfo->capabilityInfo->cryptAlgo );
  778.     size += sizeofEnumerated( cryptInfo->capabilityInfo->cryptMode );
  779.     if( !cryptInfo->privateUseDefaults )
  780.         size += sizeofAlgorithmParams( cryptInfo );
  781.     size += ( int ) sizeofObject( cryptInfo->userKeyLength );
  782.  
  783.     /* Determine the total encoded size.  If we're padding the length, we
  784.        just return the nearest KEYINFO_PADSIZE-byte value above this,
  785.        otherwise we return the real size */
  786.     size = sizeof( BYTE ) + calculateLengthSize( size ) + size;
  787.     if( addPadding && ( size & ( KEYINFO_PADSIZE - 1 ) ) )
  788.         /* We only need to pad if it's not a multiple of KEYINFO_PADSIZE
  789.            bytes long.  The three bytes added to the calculation are for the
  790.            minimum-length octet string possible for the padding */
  791.         return( ( size + 3 + ( KEYINFO_PADSIZE - 1 ) ) & ~( KEYINFO_PADSIZE - 1 ) );
  792.     return( size );
  793.     }
  794.  
  795. /* Write the key information.  Since this is only ever written to a memory
  796.    stream prior to being encrypted with a public key, there's no need to
  797.    specify the tag type.  The first function writes only the header
  798.    information (but not the key itself) for use in various locations which
  799.    need to process encryption key information formatted in a standardised
  800.    manner) */
  801.  
  802. int writeKeyInfoHeader( STREAM *stream, const CRYPT_INFO *cryptInfo,
  803.                         int keyLength )
  804.     {
  805.     CAPABILITY_INFO *capabilityInfo = cryptInfo->capabilityInfo;
  806.     int algorithmInfoSize = 0;
  807.  
  808.     /* Determine the size of the algorithm-specific components and check we
  809.        can handle this algorithm */
  810.     if( !cryptInfo->privateUseDefaults && \
  811.         ( algorithmInfoSize = sizeofAlgorithmParams( cryptInfo ) ) < 0 )
  812.         return( CRYPT_ERROR );    /* Internal error, should never happen */
  813.  
  814.     /* Write the identifier and length fields */
  815.     writeTag( stream, BER_SEQUENCE );
  816.     writeLength( stream, sizeofEnumerated( capabilityInfo->cryptAlgo ) +
  817.                  sizeofEnumerated( capabilityInfo->cryptMode ) +
  818.                  algorithmInfoSize + ( int ) sizeofObject( keyLength ) );
  819.  
  820.     /* Write the algorithm parameters */
  821.     writeAlgorithmParams( stream, capabilityInfo, cryptInfo );
  822.  
  823.     /* Write the start of the octetString which contains the key */
  824.     writeTag( stream, BER_OCTETSTRING );
  825.     writeLength( stream, keyLength );
  826.  
  827.     return( ( sGetStatus( stream ) != STREAM_OK ) ? CRYPT_ERROR : CRYPT_OK );
  828.     }
  829.  
  830. int writeKeyInfo( STREAM *stream, const CRYPT_INFO *cryptInfo,
  831.                   int *keyOffset, const BOOLEAN addPadding )
  832.     {
  833.     BYTE dummy[ CRYPT_MAX_KEYSIZE ];
  834.  
  835.     /* Write the start of the KeyInformation record */
  836.     writeKeyInfoHeader( stream, cryptInfo, cryptInfo->userKeyLength );
  837.     *keyOffset = sMemSize( stream );
  838.  
  839.     /* Insert the dummy key */
  840.     swrite( stream, dummy, cryptInfo->userKeyLength );
  841.  
  842.     /* If we want to pad the output and it's not a multiple of
  843.        KEYINFO_PADSIZE bytes long, write an octet string to make it the
  844.        right length */
  845.     if( addPadding && ( sMemSize( stream ) & ( KEYINFO_PADSIZE - 1 ) ) )
  846.         {
  847.         BYTE padding[ KEYINFO_PADSIZE ];
  848.         int padSize;
  849.  
  850.         /* Find out how long the padding data needs to be (the three-byte
  851.            value is the minimum-size octet string, the two-byte value is the
  852.            size of the octet string header) */
  853.         padSize = ( sMemSize( stream ) + 3 + ( KEYINFO_PADSIZE - 1 ) ) & \
  854.                   ~( KEYINFO_PADSIZE - 1 );
  855.         padSize -= sMemSize( stream ) + 2;
  856.  
  857.         /* Write the octet string with the padding.  It doesn't have to
  858.            be cryptographically strong, or even random for that matter,
  859.            although writing a constant string is inadvisable */
  860.         getNonce( padding, padSize );    /* Insert subliminal channel here */
  861.         writeByteString( stream, padding, padSize, DEFAULT_TAG );
  862.         }
  863.  
  864.     return( ( sGetStatus( stream ) != STREAM_OK ) ? CRYPT_ERROR : CRYPT_OK );
  865.     }
  866.  
  867. /* Read the key information.  Since this is only ever read from a memory
  868.    stream prior to being loaded into an encryption context, there's no need
  869.    to specify whether we'll read the tag type */
  870.  
  871. int readKeyInfo( STREAM *stream, CRYPT_CONTEXT *cryptContext )
  872.     {
  873.     CRYPT_INFO *cryptInfoPtr;
  874.     int readDataLength, status;
  875.     long length;
  876.  
  877.     /* Read the identifier and length fields */
  878.     if( readTag( stream ) != BER_SEQUENCE )
  879.         {
  880.         sSetError( stream, STREAM_BADDATA );
  881.         return( CRYPT_BADDATA );
  882.         }
  883.     readDataLength = readLength( stream, &length ) + 1;
  884.  
  885.     /* Read the encryption algorithm information and create an encryption
  886.        context from it */
  887.     if( cryptStatusError( length = readAlgorithmParams( stream, cryptContext, NULL ) ) )
  888.         return( ( int ) length );
  889.     readDataLength += ( int ) length;
  890.  
  891.     /* Finally, read the encryption key and load it into the encryption
  892.        context.  Like the equivalent code in writeEncryptedDataInfo(), we
  893.        never actually read the data into an octet string but load it
  894.        directly into the encryption context, so we need to duplicate most of
  895.        readOctetString() here */
  896.     if( readTag( stream ) != BER_OCTETSTRING )
  897.         {
  898.         cryptDestroyContext( *cryptContext );
  899.         sSetError( stream, STREAM_BADDATA );
  900.         return( CRYPT_BADDATA );
  901.         }
  902.     readDataLength += readLength( stream, &length ) + 1;
  903.     cryptInfoPtr = CONTEXT_TO_INFO( *cryptContext );
  904.     cryptInfoPtr->clearBuffer = TRUE;
  905.     status = cryptLoadContext( *cryptContext, stream->buffer + stream->bufPos,
  906.                                ( int ) length );
  907.     cryptInfoPtr->clearBuffer = FALSE;
  908.     if( cryptStatusError( status ) )
  909.         {
  910.         cryptDestroyContext( *cryptContext );
  911.         return( status );
  912.         }
  913.  
  914.     /* There could be padding after the key, but we don't need to do anything
  915.        with it so we can exit now */
  916.     if( sGetStatus( stream ) != STREAM_OK )
  917.         return( CRYPT_BADDATA );
  918.     return( readDataLength + ( int ) length );
  919.     }
  920.  
  921. /****************************************************************************
  922. *                                                                            *
  923. *                        Conventionally-Encrypted Key Routines                *
  924. *                                                                            *
  925. ****************************************************************************/
  926.  
  927. /* Write a conventionally encrypted key */
  928.  
  929. int writeEncryptedKey( STREAM *stream, const CRYPT_INFO *cryptInfo,
  930.                        const CRYPT_INFO *sessionKeyInfo, const BYTE *buffer,
  931.                        const int length )
  932.     {
  933.     CAPABILITY_INFO *capabilityInfo = cryptInfo->capabilityInfo;
  934.     BYTE *keyCookie = NULL;
  935.     int algorithmInfoSize = 0, controlVectorSize = 0, ivSize = 0;
  936.     int derivationInfoSize = 0, cookieSize = 0;
  937.  
  938.     /* Determine the size of the algorithm information components and check
  939.        we can handle this algorithm */
  940.     if( !cryptInfo->privateUseDefaults && \
  941.         ( algorithmInfoSize = sizeofAlgorithmParams( cryptInfo ) ) < 0 )
  942.         return( CRYPT_ERROR );    /* Internal error, should never happen */
  943.  
  944.     /* Determine the size of any optional parameters */
  945.     if( sessionKeyInfo->controlVector )
  946.         controlVectorSize = sizeofBitString( sessionKeyInfo->controlVector );
  947.     if( capabilityInfo->cryptMode != CRYPT_MODE_ECB )
  948.         ivSize = ( int ) sizeofObject( CRYPT_MAX_IVSIZE );
  949.     if( sessionKeyInfo->exportKeyCookie == TRUE || \
  950.         ( sessionKeyInfo->exportKeyCookie == CRYPT_USE_DEFAULT && \
  951.           getOptionExportKeyCookie() ) )
  952.         {
  953.         cookieSize = ( int ) sizeofObject( KEY_COOKIE_SIZE );
  954.         keyCookie = ( BYTE * ) sessionKeyInfo->keyCookie;
  955.         }
  956.     if( cryptInfo->keySetupAlgorithm != DEFAULT_KEYSETUP_ALGO || \
  957.         cryptInfo->keySetupIterations != DEFAULT_KEYSETUP_ITERATIONS )
  958.         {
  959.         /* The constant 2 is the size of the tag and length fields */
  960.         derivationInfoSize = 2 + sizeofEnumerated( sessionKeyInfo->keySetupAlgorithm ) + \
  961.                              sizeofShortInteger( sessionKeyInfo->keySetupIterations );
  962.         }
  963.  
  964.     /* Write the identifier and length fields */
  965.     writeTag( stream, BER_SEQUENCE );
  966.     writeLength( stream, sizeofEnumerated( capabilityInfo->cryptAlgo ) +
  967.                  sizeofEnumerated( capabilityInfo->cryptMode ) +
  968.                  algorithmInfoSize + derivationInfoSize + cookieSize +
  969.                  controlVectorSize + ivSize + ( int ) sizeofObject( length ) );
  970.  
  971.     /* Write the algorithm, mode, and algorithm parameters */
  972.     writeAlgorithmParams( stream, capabilityInfo, cryptInfo );
  973.  
  974.     /* Write the key derivation info if necessary */
  975.     if( derivationInfoSize )
  976.         {
  977.         writeCtag( stream, CTAG_CK_DERIVATIONINFO, TRUE );
  978.         writeLength( stream, derivationInfoSize - 2 );
  979.         writeEnumerated( stream, cryptInfo->keySetupAlgorithm,
  980.                          DEFAULT_TAG );
  981.         writeShortInteger( stream, cryptInfo->keySetupIterations,
  982.                            DEFAULT_TAG );
  983.         }
  984.  
  985.     /* Write the key cookie and control vector */
  986.     writeKeyParams( stream, keyCookie, CTAG_CK_KEYCOOKIE,
  987.                     sessionKeyInfo->controlVector, CTAG_CK_CONTROLVECTOR );
  988.  
  989.     /* Write the encryted key.  cryptLoadIV() pads the IV with zeroes if need
  990.        be so we don't need to worry about the IV not being CRYPT_MAX_IVSIZE
  991.        in length */
  992.     if( capabilityInfo->cryptMode != CRYPT_MODE_ECB )
  993.         writeByteString( stream, cryptInfo->iv, CRYPT_MAX_IVSIZE, CTAG_CK_IV );
  994.     writeByteString( stream, buffer, length, DEFAULT_TAG );
  995.  
  996.     /* Clean up */
  997.     wrapExplicitTag( stream, BER_ENCRYPTED_KEY, 0 );
  998.     return( ( sGetStatus( stream ) != STREAM_OK ) ? CRYPT_ERROR : CRYPT_OK );
  999.     }
  1000.  
  1001. /* Read a conventionally encrypted key */
  1002.  
  1003. int readEncryptedKey( STREAM *stream, const CRYPT_INFO *cryptInfo,
  1004.                       CRYPT_OBJECT_INFO *cryptObjectInfo, int *keyInfoLength )
  1005.     {
  1006.     CRYPT_OBJECT_TYPE objectType;
  1007.     int readDataLength, tagLength, status;
  1008.     long length;
  1009.  
  1010.     /* Read the general information at the start of the encrypted key record */
  1011.     if( ( readDataLength = readObjectWrapper( stream, &objectType, &length ) ) < 0 )
  1012.         return( readDataLength );
  1013.     if( objectType != CRYPT_OBJECT_ENCRYPTED_KEY )
  1014.         return( CRYPT_BADDATA );
  1015.  
  1016.     /* Read the encryption algorithm information and make sure the key
  1017.        we'll be using to import it matches the requirements.  Checking the
  1018.        algorithm-specific parameters for the encryption context is a bit too
  1019.        complex since they're processed internally by the library routines
  1020.        when the context is created and may not be present in an easily-
  1021.        accessible form.  If the caller has used cryptQueryObject() to get the
  1022.        parameters to create the context then they'll be set up correctly
  1023.        anyway, and the key decrypt will catch any errors if they're not */
  1024.     status = readCKObject( stream, cryptObjectInfo );
  1025.     if( cryptStatusError( status ) )
  1026.         return( status );
  1027.     if( cryptInfo->capabilityInfo->cryptAlgo != cryptObjectInfo->cryptAlgo || \
  1028.         cryptInfo->capabilityInfo->cryptMode != cryptObjectInfo->cryptMode )
  1029.         return( CRYPT_BADPARM );
  1030.     readDataLength += status;
  1031.  
  1032.     /* Read the IV if necessary.  Strictly speaking we don't need to look for
  1033.        the context-specific tag for the IV since we can tell whether it'll be
  1034.        present based on the encryption mode */
  1035.     tagLength = checkReadCtag( stream, CTAG_CK_IV, FALSE );
  1036.     if( tagLength )
  1037.         readDataLength += readStaticOctetStringData( stream,
  1038.                             cryptObjectInfo->iv, &cryptObjectInfo->ivSize,
  1039.                             CRYPT_MAX_IVSIZE ) + tagLength;
  1040.  
  1041.     /* Finally, read the start of the encrypted key.  We never read the data
  1042.        itself since it's passed directly to the decrypt function */
  1043.     if( readTag( stream ) != BER_OCTETSTRING )
  1044.         {
  1045.         sSetError( stream, STREAM_BADDATA );
  1046.         return( CRYPT_BADDATA );
  1047.         }
  1048.     readDataLength += readLength( stream, &length ) + 1;
  1049.     *keyInfoLength = ( int ) length;
  1050.  
  1051.     if( sGetStatus( stream ) != STREAM_OK )
  1052.         return( CRYPT_BADDATA );
  1053.     return( readDataLength + *keyInfoLength );
  1054.     }
  1055.  
  1056. /****************************************************************************
  1057. *                                                                            *
  1058. *                            PKC-Encrypted Key Routines                        *
  1059. *                                                                            *
  1060. ****************************************************************************/
  1061.  
  1062. /* Write a PKC-encrypted key.  This gets a bit complicated because there are
  1063.    two different types of records, a Diffie-Hellman one where the
  1064.    conventional-encryption parameters are stored as part of the key record,
  1065.    and a general PKC one where the conventional-encryption parameters are
  1066.    wrapped up alongside the encrypted key */
  1067.  
  1068. int writePKCEncryptedKey( STREAM *stream, const CRYPT_INFO *pkcInfo,
  1069.                           const CRYPT_INFO *sessionKeyInfo,
  1070.                           const BYTE *buffer, const int length )
  1071.     {
  1072.     CAPABILITY_INFO *capabilityInfo = sessionKeyInfo->capabilityInfo;
  1073.     CRYPT_ALGO pkcAlgo = pkcInfo->capabilityInfo->cryptAlgo;
  1074.     INTEGER encryptedKey;
  1075.     BYTE *keyCookie = NULL;
  1076.     int controlVectorSize = 0, cookieSize = 0;
  1077.  
  1078.     /* Set up an integer which corresponds to the buffer contents (these are
  1079.        always big-endian so there's no need to perform an conversion) */
  1080.     newInteger( &encryptedKey, 0 );
  1081.     encryptedKey.longInteger = ( BYTE * ) buffer;
  1082.     encryptedKey.precision = length;
  1083.  
  1084.     /* Determine the size of any optional parameters */
  1085.     if( sessionKeyInfo->controlVector )
  1086.         controlVectorSize = sizeofBitString( sessionKeyInfo->controlVector );
  1087.     if( pkcAlgo != CRYPT_ALGO_DH && \
  1088.         ( sessionKeyInfo->exportKeyCookie == TRUE || \
  1089.           ( sessionKeyInfo->exportKeyCookie == CRYPT_USE_DEFAULT && \
  1090.             getOptionExportKeyCookie() ) ) )
  1091.         {
  1092.         cookieSize = ( int ) sizeofObject( KEY_COOKIE_SIZE );
  1093.         keyCookie = ( BYTE * ) sessionKeyInfo->keyCookie;
  1094.         }
  1095.  
  1096.     /* Write the appropriate record depending on whether it's a DH or generic
  1097.        PKC */
  1098.     writeTag( stream, BER_SEQUENCE );
  1099.     if( pkcAlgo == CRYPT_ALGO_DH )
  1100.         {
  1101.         int algorithmInfoSize = 0;
  1102.  
  1103.         /* Determine the size of the algorithm information components and
  1104.            check we can handle this algorithm */
  1105.         if( !sessionKeyInfo->privateUseDefaults && \
  1106.             ( algorithmInfoSize = sizeofAlgorithmParams( sessionKeyInfo ) ) < 0 )
  1107.             return( CRYPT_ERROR );    /* Internal error, should never happen */
  1108.         algorithmInfoSize += sizeofEnumerated( capabilityInfo->cryptAlgo ) +
  1109.                              sizeofEnumerated( capabilityInfo->cryptMode );
  1110.  
  1111.         /* Write the length field, PKC algorithm type, conventional algorithm
  1112.            parameters, and a dummy cookie */
  1113.         writeLength( stream,  +
  1114.                      sizeofEnumerated( pkcAlgo ) + algorithmInfoSize +
  1115.                      controlVectorSize + sizeofInteger( &encryptedKey ) );
  1116.         writeRawObject( stream, pkcInfo->keyID, pkcInfo->keyIDlength );
  1117.         writeEnumerated( stream, pkcAlgo, DEFAULT_TAG );
  1118.         writeCtag( stream, CTAG_PK_ALGOINFO, TRUE );
  1119.         writeLength( stream, algorithmInfoSize );
  1120.         writeAlgorithmParams( stream, capabilityInfo, sessionKeyInfo );
  1121.         }
  1122.     else
  1123.         {
  1124.         /* Write the length field, PKC algorithm type, and key cookie */
  1125.         writeLength( stream, pkcInfo->keyIDlength +
  1126.                      sizeofEnumerated( pkcAlgo ) + cookieSize +
  1127.                      controlVectorSize + sizeofInteger( &encryptedKey ) );
  1128.         writeRawObject( stream, pkcInfo->keyID, pkcInfo->keyIDlength );
  1129.         writeEnumerated( stream, pkcAlgo, DEFAULT_TAG );
  1130.         }
  1131.     writeKeyParams( stream, keyCookie, CTAG_PK_KEYCOOKIE,
  1132.                     sessionKeyInfo->controlVector, CTAG_PK_CONTROLVECTOR );
  1133.  
  1134.     /* Write the encryted key */
  1135.     writeInteger( stream, &encryptedKey, DEFAULT_TAG );
  1136.  
  1137.     /* Clean up */
  1138.     encryptedKey.longInteger = NULL;
  1139.     deleteInteger( &encryptedKey );
  1140.  
  1141.     wrapExplicitTag( stream, BER_PKCENCRYPTED_KEY, 0 );
  1142.     return( ( sGetStatus( stream ) != STREAM_OK ) ? CRYPT_ERROR : CRYPT_OK );
  1143.     }
  1144.  
  1145. /* Read a PKC-encrypted key */
  1146.  
  1147. int readPKCEncryptedKey( STREAM *stream, CRYPT_INFO *pkcInfo,
  1148.                          CRYPT_CONTEXT *sessionKeyContext,
  1149.                          CRYPT_OBJECT_INFO *cryptObjectInfo )
  1150.     {
  1151.     CAPABILITY_INFO *capabilityInfo = pkcInfo->capabilityInfo;
  1152.     CRYPT_OBJECT_TYPE objectType;
  1153.     CRYPT_ALGO cryptAlgo;
  1154.     int readDataLength;
  1155.     long length;
  1156.  
  1157.     /* Read the general information at the start of the encrypted key record */
  1158.     if( ( readDataLength = readObjectWrapper( stream, &objectType, &length ) ) < 0 )
  1159.         return( readDataLength );
  1160.     if( objectType != CRYPT_OBJECT_PKCENCRYPTED_KEY )
  1161.         return( CRYPT_BADDATA );
  1162.     if( ( readDataLength = readPKObject( stream, pkcInfo->keyID,
  1163.                                 &pkcInfo->keyIDlength, &cryptAlgo ) ) < 0 )
  1164.         return( readDataLength );
  1165.     if( cryptAlgo != capabilityInfo->cryptAlgo )
  1166.         return( CRYPT_NOTAVAIL );
  1167.  
  1168.     /* Read the encrypted key-specific parameters if necessary */
  1169.     readDataLength += readPKKeyObject( stream, cryptAlgo, sessionKeyContext,
  1170.                                        cryptObjectInfo );
  1171.  
  1172.     /* Finally, read the start of the encrypted key.  We never read the data
  1173.        itself since it's passed directly to the PKC decrypt function */
  1174.     if( readTag( stream ) != BER_INTEGER )
  1175.         {
  1176.         if( cryptAlgo == CRYPT_ALGO_DH )
  1177.             cryptDestroyContext( *sessionKeyContext );
  1178.         sSetError( stream, STREAM_BADDATA );
  1179.         return( CRYPT_BADDATA );
  1180.         }
  1181.     readDataLength += readLength( stream, &length ) + 1;
  1182.  
  1183.     if( sGetStatus( stream ) != STREAM_OK )
  1184.         return( CRYPT_BADDATA );
  1185.     return( readDataLength + ( int ) length );
  1186.     }
  1187.  
  1188. /****************************************************************************
  1189. *                                                                            *
  1190. *                                Signature Routines                            *
  1191. *                                                                            *
  1192. ****************************************************************************/
  1193.  
  1194. /* Write/read the message digest information record which is contained inside
  1195.    the signature */
  1196.  
  1197. int sizeofMessageDigestInfo( const MESSAGE_DIGEST *messageDigest )
  1198.     {
  1199.     int size = ( int ) sizeofObject( 8 ) + sizeofMessageDigest( messageDigest );
  1200.  
  1201.     return( sizeof( BYTE ) + calculateLengthSize( size ) + size );
  1202.     }
  1203.  
  1204. int writeMessageDigestInfo( STREAM *stream, const MESSAGE_DIGEST *messageDigest )
  1205.     {
  1206.     BYTE nonce[ 8 ];
  1207.  
  1208.     /* Create the nonce
  1209.     getNonce( nonce, 8 );
  1210.  
  1211.     /* Write the identifier and length fields */
  1212.     writeTag( stream, BER_SEQUENCE );
  1213.     writeLength( stream, ( int ) sizeofObject( 8 ) +
  1214.                  sizeofMessageDigest( messageDigest ) );
  1215.  
  1216.     /* Write the nonce and message digest */
  1217.     writeByteString( stream, nonce, 8, DEFAULT_TAG );
  1218.     writeMessageDigest( stream, messageDigest, DEFAULT_TAG );
  1219.  
  1220.     return( ( sGetStatus( stream ) != STREAM_OK ) ? CRYPT_ERROR : CRYPT_OK );
  1221.     }
  1222.  
  1223. int readMessageDigestInfo( STREAM *stream, MESSAGE_DIGEST *messageDigest )
  1224.     {
  1225.     BYTE nonce[ 8 ];
  1226.     int readDataLength, dummyInt;
  1227.     long dummy;
  1228.  
  1229.     /* Read the identifier and length fields */
  1230.     if( readTag( stream ) != BER_SEQUENCE )
  1231.         {
  1232.         sSetError( stream, STREAM_BADDATA );
  1233.         return( CRYPT_BADDATA );
  1234.         }
  1235.     readDataLength = readLength( stream, &dummy ) + 1;
  1236.  
  1237.     /* Read the nonce and message digest */
  1238.     readDataLength += readStaticOctetString( stream, nonce, &dummyInt, 8 );
  1239.     readDataLength += readMessageDigest( stream, messageDigest );
  1240.  
  1241.     if( sGetStatus( stream ) != STREAM_OK )
  1242.         return( CRYPT_BADDATA );
  1243.     return( readDataLength );
  1244.     }
  1245.  
  1246. /* Write the signature */
  1247.  
  1248. int writeSignature( STREAM *stream, const CRYPT_INFO *pkcInfo,
  1249.                     const BYTE *buffer, const int length )
  1250.     {
  1251.     CRYPT_ALGO pkcAlgo = pkcInfo->capabilityInfo->cryptAlgo;
  1252.  
  1253.     /* Write the identifier and length fields.  We evaluate the size of the
  1254.        signature itself as the size of the BIT STRING needed to encapsulate
  1255.        it */
  1256.     writeTag( stream, BER_SEQUENCE );
  1257.     writeLength( stream, pkcInfo->keyIDlength + sizeofEnumerated( pkcAlgo ) +
  1258.                  sizeofObject( length + 1 ) );
  1259.  
  1260.     /* Write the key ID and PKC algorithm type */
  1261.     writeRawObject( stream, pkcInfo->keyID, pkcInfo->keyIDlength );
  1262.     writeEnumerated( stream, pkcAlgo, DEFAULT_TAG );
  1263.  
  1264.     /* Write the signature encapsulated in a BIT STRING.  The signature is
  1265.        always big-endian so there's no need to perform a conversion */
  1266.     writeTag( stream, BER_BITSTRING );
  1267.     writeLength( stream, length + 1 );
  1268.     sputc( stream, 0 );        /* Write bit remainder octet */
  1269.     writeRawObject( stream, buffer, length );
  1270.  
  1271.     wrapExplicitTag( stream, BER_SIGNATURE, 0 );
  1272.     return( ( sGetStatus( stream ) != STREAM_OK ) ? CRYPT_ERROR : CRYPT_OK );
  1273.     }
  1274.  
  1275. /* Read a signature */
  1276.  
  1277. int readSignature( STREAM *stream, CRYPT_INFO *pkcInfo )
  1278.     {
  1279.     CAPABILITY_INFO *capabilityInfo = pkcInfo->capabilityInfo;
  1280.     CRYPT_OBJECT_TYPE objectType;
  1281.     CRYPT_ALGO cryptAlgo;
  1282.     int readDataLength, tagLength;
  1283.     long length;
  1284.  
  1285.     /* Read the general information at the start of the signature record */
  1286.     if( ( readDataLength = readObjectWrapper( stream, &objectType, &length ) ) < 0 )
  1287.         return( readDataLength );
  1288.     if( objectType != CRYPT_OBJECT_SIGNATURE )
  1289.         return( CRYPT_BADPARM );
  1290.     if( ( readDataLength = readPKObject( stream, pkcInfo->keyID,
  1291.                                 &pkcInfo->keyIDlength, &cryptAlgo ) ) < 0 )
  1292.         return( readDataLength );
  1293.     if( cryptAlgo != capabilityInfo->cryptAlgo )
  1294.         return( CRYPT_NOTAVAIL );
  1295.  
  1296.     /* Read the algorithm-specific parameters if necessary */
  1297.     tagLength = checkReadCtag( stream, CTAG_SG_ALGOINFO, TRUE );
  1298.     if( tagLength )
  1299.         {
  1300.         readLength( stream, &length );
  1301.         readDataLength += ( int ) length + tagLength;
  1302.         switch( cryptAlgo )
  1303.             {
  1304.             default:
  1305.                 return( CRYPT_NOALGO );
  1306.             }
  1307.         }
  1308.  
  1309.     /* Read the signature cookie if necessary */
  1310.     tagLength = checkReadCtag( stream, CTAG_SG_SIGNATURECOOKIE, TRUE );
  1311.     if( tagLength )
  1312.         /* We can't handle signature cookies yet, just skip it for now */
  1313.         readDataLength += readUniversalData( stream ) + tagLength;
  1314.  
  1315.     /* Finally, read the start of the signature itself.  We never read the
  1316.        data since it's passed directly to the PKC function */
  1317.     if( readTag( stream ) != BER_BITSTRING )
  1318.         {
  1319.         sSetError( stream, STREAM_BADDATA );
  1320.         return( CRYPT_BADDATA );
  1321.         }
  1322.     readDataLength += readLength( stream, &length ) + 2;
  1323.     sgetc( stream );        /* Read bit remainder octet */
  1324.  
  1325.     if( sGetStatus( stream ) != STREAM_OK )
  1326.         return( CRYPT_BADDATA );
  1327.     return( readDataLength + ( int ) length );
  1328.     }
  1329.  
  1330. /****************************************************************************
  1331. *                                                                            *
  1332. *                                Data Object Routines                        *
  1333. *                                                                            *
  1334. ****************************************************************************/
  1335.  
  1336. /* Write the start of a RawData or NonData object */
  1337.  
  1338. int writeBasicObject( STREAM *stream, const BOOLEAN isContinued,
  1339.                       const long dataLength, const BOOLEAN isDataObject )
  1340.     {
  1341.     int continuationLength = ( isContinued ) ? sizeofBoolean() : 0;
  1342.  
  1343.     /* Write the identifier and length fields */
  1344.     writeTag( stream, BER_SEQUENCE );
  1345.     writeLength( stream, continuationLength + sizeofObject( dataLength ) );
  1346.  
  1347.     /* Write the continuation flag if necessary */
  1348.     if( isContinued )
  1349.         writeBoolean( stream, TRUE, DEFAULT_TAG );
  1350.  
  1351.     /* Write the start of the OCTET STRING field */
  1352.     writeTag( stream, BER_OCTETSTRING );
  1353.     writeLength( stream, dataLength );
  1354.  
  1355.     wrapExplicitTag( stream, isDataObject ? BER_RAW_DATA : BER_NONDATA,
  1356.                      dataLength );
  1357.     return( ( sGetStatus( stream ) != STREAM_OK ) ? CRYPT_ERROR : CRYPT_OK );
  1358.     }
  1359.  
  1360. /* Read the start of a RawData or NonData object */
  1361.  
  1362. int readBasicObject( STREAM *stream, BOOLEAN *isContinued, long *dataLength )
  1363.     {
  1364.     int readDataLength = 0;
  1365.  
  1366.     /* Read the continuation flag if necessary */
  1367.     if( checkReadTag( stream, BER_BOOLEAN ) )
  1368.         readDataLength += readBooleanData( stream, isContinued ) + 1;
  1369.     else
  1370.         *isContinued = FALSE;
  1371.  
  1372.     /* Read the start of the OCTET STRING field */
  1373.     if( readTag( stream ) != BER_OCTETSTRING )
  1374.         {
  1375.         sSetError( stream, STREAM_BADDATA );
  1376.         return( CRYPT_BADDATA );
  1377.         }
  1378.     readDataLength += readLength( stream, dataLength ) + 1;
  1379.  
  1380.     if( sGetStatus( stream ) != STREAM_OK )
  1381.         return( CRYPT_BADDATA );
  1382.     return( readDataLength );
  1383.     }
  1384.  
  1385. /* Write the start of an EncryptedData object */
  1386.  
  1387. int writeEncryptedObject( STREAM *stream, const BOOLEAN isContinued,
  1388.                           const long dataLength,
  1389.                           const CRYPT_INFO *cryptInfoPtr )
  1390.     {
  1391.     int continuationLength = ( isContinued ) ? sizeofBoolean() : 0;
  1392.     int cookieSize = ( cryptInfoPtr->exportKeyCookie == TRUE || \
  1393.                        ( cryptInfoPtr->exportKeyCookie == CRYPT_USE_DEFAULT && \
  1394.                          getOptionExportKeyCookie() ) ) ? \
  1395.                      ( int ) sizeofObject( KEY_COOKIE_SIZE ) : 0;
  1396.  
  1397.     /* Write the identifier and length fields */
  1398.     writeTag( stream, BER_SEQUENCE );
  1399.     writeLength( stream, continuationLength + cookieSize +
  1400.                  sizeofObject( CRYPT_MAX_IVSIZE ) +
  1401.                  sizeofObject( dataLength ) );
  1402.  
  1403.     /* Write the continuation flag if necessary */
  1404.     if( isContinued )
  1405.         writeBoolean( stream, TRUE, DEFAULT_TAG );
  1406.  
  1407.     /* Write the key cookie and IV.  cryptLoadIV() pads the IV with zeroes if
  1408.        need be so we don't need to worry about the IV not being
  1409.        CRYPT_MAX_IVSIZE in length */
  1410.     if( cookieSize )
  1411.         writeByteString( stream, cryptInfoPtr->keyCookie, KEY_COOKIE_SIZE,
  1412.                          CTAG_ED_KEYCOOKIE );
  1413.     writeByteString( stream, cryptInfoPtr->iv, CRYPT_MAX_IVSIZE, DEFAULT_TAG );
  1414.  
  1415.     /* Write the start of the OCTET STRING field for the encrypted data */
  1416.     writeTag( stream, BER_OCTETSTRING );
  1417.     writeLength( stream, dataLength );
  1418.  
  1419.     wrapExplicitTag( stream, BER_ENCRYPTED_DATA, dataLength );
  1420.     return( ( sGetStatus( stream ) != STREAM_OK ) ? CRYPT_ERROR : CRYPT_OK );
  1421.     }
  1422.  
  1423. /* Read the start of an EncryptedData object */
  1424.  
  1425. int readEncryptedObject( STREAM *stream, BOOLEAN *isContinued,
  1426.                          long *dataLength,
  1427.                          CRYPT_OBJECT_INFO *cryptObjectInfo )
  1428.     {
  1429.     int readDataLength = 0, tagLength;
  1430.  
  1431.     /* Read the continuation flag if necessary */
  1432.     if( checkReadTag( stream, BER_BOOLEAN ) )
  1433.         readDataLength += readBooleanData( stream, isContinued ) + 1;
  1434.     else
  1435.         *isContinued = FALSE;
  1436.  
  1437.     /* Read the key cookie if necessary */
  1438.     tagLength = checkReadCtag( stream, CTAG_ED_KEYCOOKIE, FALSE );
  1439.     if( tagLength )
  1440.         readDataLength += readCookie( stream, cryptObjectInfo->cookie,
  1441.                     &cryptObjectInfo->cookieSize, KEY_COOKIE_SIZE ) + tagLength;
  1442.  
  1443.     /* Read the IV */
  1444.     readDataLength += readStaticOctetString( stream, cryptObjectInfo->iv,
  1445.                                 &cryptObjectInfo->ivSize, CRYPT_MAX_IVSIZE );
  1446.     if( cryptObjectInfo->ivSize != CRYPT_MAX_IVSIZE )
  1447.         {
  1448.         sSetError( stream, STREAM_BADDATA );
  1449.         return( CRYPT_BADDATA );
  1450.         }
  1451.  
  1452.     /* Read the start of the OCTET STRING field */
  1453.     if( readTag( stream ) != BER_OCTETSTRING )
  1454.         {
  1455.         sSetError( stream, STREAM_BADDATA );
  1456.         return( CRYPT_BADDATA );
  1457.         }
  1458.     readDataLength += readLength( stream, dataLength ) + 1;
  1459.  
  1460.     if( sGetStatus( stream ) != STREAM_OK )
  1461.         return( CRYPT_BADDATA );
  1462.     return( readDataLength );
  1463.     }
  1464.  
  1465. /* Write the start of a SignedData object */
  1466.  
  1467. int writeSignedObject( STREAM *stream, const BOOLEAN isContinued,
  1468.                        const CRYPT_INFO *cryptInfoPtr, const long dataLength )
  1469.     {
  1470.     int continuationLength = ( isContinued ) ? sizeofBoolean() : 0;
  1471.     int cookieSize = ( cryptInfoPtr->exportSigCookie == TRUE || \
  1472.                        ( cryptInfoPtr->exportSigCookie == CRYPT_USE_DEFAULT && \
  1473.                          getOptionExportSigCookie() ) ) ? \
  1474.                      ( int ) sizeofObject( SIGNATURE_COOKIE_SIZE ) : 0;
  1475.     int mdInfoSize = 0, noHashes;
  1476.  
  1477.     /* Write the identifier and length fields */
  1478.     writeTag( stream, BER_SEQUENCE );
  1479.     writeLength( stream, continuationLength + cookieSize +
  1480.                  sizeofObject( dataLength ) );
  1481.  
  1482.     /* Write the continuation flag if necessary */
  1483.     if( isContinued )
  1484.         writeBoolean( stream, TRUE, DEFAULT_TAG );
  1485.  
  1486.     /* Write the signature cookie and hash algorithm information */
  1487.     if( cookieSize )
  1488.         writeByteString( stream, cryptInfoPtr->sigCookie,
  1489.                          SIGNATURE_COOKIE_SIZE, CTAG_SD_SIGNATURECOOKIE );
  1490.  
  1491.     /* Evaluate the size of the SET OF MessageDigestParams */
  1492.     for( noHashes = 0; noHashes < 1; noHashes++ )
  1493.         {
  1494.         CRYPT_ALGO algorithm = cryptInfoPtr->capabilityInfo->cryptAlgo;
  1495.         int parameter = 0, size;
  1496.  
  1497.         /* Get any optional algorithm-specific parameters */
  1498.         if( algorithm == CRYPT_ALGO_SHA )
  1499.             parameter = getSHAinfo( cryptInfoPtr );
  1500.  
  1501.         /* Determine the size of this set of algorithm parameters */
  1502.         size = sizeofMessageDigestParams( algorithm, parameter, 0 );
  1503.         mdInfoSize += sizeof( BYTE ) + calculateLengthSize( size ) + size;
  1504.         }
  1505.  
  1506.     /* Now that we know the total size of the collection of algorithm
  1507.        parameters, write the SET OF header */
  1508.     writeTag( stream, BER_SET );
  1509.     writeLength( stream, mdInfoSize );
  1510.  
  1511.     /* Finally, write the collection of algorithm parameters */
  1512.     for( noHashes = 0; noHashes < 1; noHashes++ )
  1513.         {
  1514.         CRYPT_ALGO algorithm = cryptInfoPtr->capabilityInfo->cryptAlgo;
  1515.         int parameter = 0;
  1516.  
  1517.         /* Get any optional algorithm-specific parameters */
  1518.         if( algorithm == CRYPT_ALGO_SHA )
  1519.             parameter = getSHAinfo( cryptInfoPtr );
  1520.  
  1521.         /* Determine the size of this set of algorithm parameters */
  1522.         writeMessageDigestParams( stream, algorithm, parameter, 0, DEFAULT_TAG );
  1523.         }
  1524.  
  1525.     wrapExplicitTag( stream, BER_SIGNED_DATA, dataLength );
  1526.     return( ( sGetStatus( stream ) != STREAM_OK ) ? CRYPT_ERROR : CRYPT_OK );
  1527.     }
  1528.  
  1529. /* Read the start of a SignedData object */
  1530.  
  1531. int readSignedObject( STREAM *stream, BOOLEAN *isContinued,
  1532.                       CRYPT_OBJECT_INFO *cryptObjectInfo )
  1533.     {
  1534.     int readDataLength = 0, tagLength;
  1535.     long dataLength;
  1536.  
  1537.     /* Read the continuation flag if necessary */
  1538.     if( checkReadTag( stream, BER_BOOLEAN ) )
  1539.         readDataLength += readBooleanData( stream, isContinued ) + 1;
  1540.     else
  1541.         *isContinued = FALSE;
  1542.  
  1543.     /* Read the signature cookie if necessary */
  1544.     tagLength = checkReadCtag( stream, CTAG_SD_SIGNATURECOOKIE, FALSE );
  1545.     if( tagLength )
  1546.         readDataLength += readCookie( stream, cryptObjectInfo->cookie,
  1547.                                       &cryptObjectInfo->cookieSize,
  1548.                                       SIGNATURE_COOKIE_SIZE ) + tagLength;
  1549.  
  1550.     /* Finally, read the collection of algorithm parameters */
  1551.     if( readTag( stream ) != BER_SET )
  1552.         {
  1553.         sSetError( stream, STREAM_BADDATA );
  1554.         return( CRYPT_BADDATA );
  1555.         }
  1556.     readDataLength += readLength( stream, &dataLength ) + 1;
  1557.     readDataLength += ( int ) dataLength;
  1558.     while( dataLength > 0 )
  1559.         {
  1560.         int parameter, parameterLength;
  1561.  
  1562.         /* Read the message digest algorithm information and optional
  1563.            parameters */
  1564.         parameterLength = readMessageDigestParams( stream,
  1565.                             &cryptObjectInfo->cryptAlgo, ¶meter, TRUE );
  1566.         dataLength -= parameterLength;
  1567.         if( parameterLength <= 0 )
  1568.             return( parameterLength );    /* Error in reading data */
  1569.  
  1570.         /* Handle any extended parameters area if necessary (we can reuse the
  1571.            IV memory because it's only used for conventional algorithms).
  1572.            Since the only algorithm with parameters is SHA and this is
  1573.            checked for by readMessageDigestParams(), we can safely assume SHA
  1574.            here */
  1575.         if( parameter )
  1576.             {
  1577.             cryptObjectInfo->cryptContextExInfo = cryptObjectInfo->iv;
  1578.             ( ( CRYPT_INFO_SHA * ) cryptObjectInfo->cryptContextExInfo )->isSHA = parameter;
  1579.             }
  1580.         else
  1581.             cryptObjectInfo->cryptContextExInfo = ( void * ) CRYPT_UNUSED;
  1582.  
  1583.         /* In theory we would just keep going until we'd read the entire SET
  1584.            OF values, but currently we can only handle sets of size one */
  1585.         while( dataLength > 0 )
  1586.             if( sgetc( stream ) < 0 )
  1587.                 break;
  1588.         }
  1589.  
  1590.     if( sGetStatus( stream ) != STREAM_OK )
  1591.         return( CRYPT_BADDATA );
  1592.     return( readDataLength );
  1593.     }
  1594.