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

  1. /****************************************************************************
  2. *                                                                            *
  3. *                        cryptlib Object Management Routines                    *
  4. *                        Copyright Peter Gutmann 1995-1996                    *
  5. *                                                                            *
  6. ****************************************************************************/
  7.  
  8. #include <stdlib.h>
  9. #include <string.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. /****************************************************************************
  18. *                                                                            *
  19. *                            Object Management Functions                        *
  20. *                                                                            *
  21. ****************************************************************************/
  22.  
  23. /* Query an object */
  24.  
  25. CRET cryptQueryObject( const void CPTR object,
  26.                        CRYPT_OBJECT_INFO CPTR cryptObjectInfo )
  27.     {
  28.     CRYPT_OBJECT_TYPE objectType;
  29.     STREAM stream;
  30.     BOOLEAN isContinued;
  31.     long length;
  32.     int headerSize, status;
  33.  
  34.     /* Perform basic error checking */
  35.     if( object == NULL )
  36.         return( CRYPT_BADPARM1 );
  37.     if( cryptObjectInfo == NULL )
  38.         return( CRYPT_BADPARM2 );
  39.  
  40.     /* Clear the query information in case we can't do anything with the
  41.        object */
  42.     memset( cryptObjectInfo, 0, sizeof( CRYPT_OBJECT_INFO ) );
  43.  
  44.     /* Read the information from the start of the object */
  45.     sMemConnect( &stream, ( void * ) object, STREAMSIZE_UNKNOWN );
  46.     status = readObjectWrapper( &stream, &objectType, &length );
  47.     if( cryptStatusError( status ) )
  48.         {
  49.         sMemDisconnect( &stream );
  50.         return( status );
  51.         }
  52.     cryptObjectInfo->type = objectType;
  53.     cryptObjectInfo->size = length;
  54.     headerSize = status;
  55.  
  56.     /* If it's encrypted data, read the continuation field, key cookie, and
  57.        IV, and work out the header and payload size */
  58.     if( objectType == CRYPT_OBJECT_ENCRYPTED_DATA )
  59.         {
  60.         status = readEncryptedObject( &stream, &isContinued, &length,
  61.                                       cryptObjectInfo );
  62.         if( !cryptStatusError( status ) )
  63.             {
  64.             cryptObjectInfo->headerSize = headerSize + status;
  65.             cryptObjectInfo->payloadSize = length;
  66.             status = CRYPT_OK;    /* The readXXX() functions return a byte count */
  67.             }
  68.         }
  69.  
  70.     /* If it's raw data or non-data, read the continuation field and work out
  71.        the header and payload size */
  72.     if( objectType == CRYPT_OBJECT_RAW_DATA || \
  73.         objectType == CRYPT_OBJECT_NONDATA )
  74.         {
  75.         status = readBasicObject( &stream, &isContinued, &length );
  76.         if( !cryptStatusError( status ) )
  77.             {
  78.             cryptObjectInfo->headerSize = headerSize + status;
  79.             cryptObjectInfo->payloadSize = length;
  80.             status = CRYPT_OK;    /* The readXXX() functions return a byte count */
  81.             }
  82.         }
  83.  
  84.     /* If it's a signed data object, read the signature cookie and hash
  85.        algorithm details */
  86.     if( objectType == CRYPT_OBJECT_SIGNED_DATA )
  87.         {
  88.         status = readSignedObject( &stream, &isContinued,
  89.                                    cryptObjectInfo );
  90.         if( !cryptStatusError( status ) )
  91.             {
  92.             /* We can't determine the payload size directly because a
  93.                SignedData object directly encapsulates arbitrary object types
  94.                whose length gets difficult to determine without recursively
  95.                reading them as well, so we calculate it as ( objectSize -
  96.                headerSize ) */
  97.             cryptObjectInfo->cryptMode = CRYPT_MODE_PKC;
  98.             cryptObjectInfo->headerSize = headerSize + status;
  99.             cryptObjectInfo->payloadSize = cryptObjectInfo->size -
  100.                                            cryptObjectInfo->headerSize;
  101.             status = CRYPT_OK;    /* The readXXX() functions return a byte count */
  102.             }
  103.         }
  104.  
  105.     /* If it's a conventional-encrypted key object, read the encryption
  106.        algorithm details */
  107.     if( objectType == CRYPT_OBJECT_ENCRYPTED_KEY )
  108.         {
  109.         status = readCKObject( &stream, cryptObjectInfo );
  110.         if( !cryptStatusError( status ) )
  111.             status = CRYPT_OK;    /* The readXXX() functions return a byte count */
  112.  
  113.         /* Set the header size information.  For this type of object the
  114.            payload size is always zero */
  115.         if( cryptStatusOK( status ) )
  116.             cryptObjectInfo->headerSize = ( int ) cryptObjectInfo->size;
  117.         }
  118.  
  119.     /* If it's a PKC-encrypted key or signature object, read the PKC
  120.        details */
  121.     if( objectType == CRYPT_OBJECT_PKCENCRYPTED_KEY || \
  122.         objectType == CRYPT_OBJECT_SIGNATURE )
  123.         {
  124.         CRYPT_ALGO cryptAlgo;
  125.         BYTE keyID[ CRYPT_MAX_KEYIDSIZE ];
  126.         int keyIDsize;
  127.  
  128.         /* Read the basic PKC details */
  129.         status = readPKObject( &stream, keyID, &keyIDsize, &cryptAlgo );
  130.         if( !cryptStatusError( status ) )
  131.             {
  132.             cryptObjectInfo->cryptAlgo = cryptAlgo;
  133.             cryptObjectInfo->cryptMode = CRYPT_MODE_PKC;
  134.             memcpy( cryptObjectInfo->keyID, keyID, keyIDsize );
  135.             cryptObjectInfo->keyIDsize = keyIDsize;
  136.  
  137.             /* Read further information depending on the object type */
  138.             if( objectType == CRYPT_OBJECT_SIGNATURE )
  139.                 status = CRYPT_OK;    /* The readXXX() fns.return a byte count */
  140.             else
  141.                 {
  142.                 status = readPKKeyObject( &stream, cryptAlgo, NULL,
  143.                                           cryptObjectInfo );
  144.                 if( !cryptStatusError( status ) )
  145.                     status = CRYPT_OK;    /* The readXXX() fns.return a byte count */
  146.                 }
  147.  
  148.             /* Set the header size information.  For this type of object the
  149.                payload size is always zero */
  150.             if( cryptStatusOK( status ) )
  151.                 cryptObjectInfo->headerSize = ( int ) cryptObjectInfo->size;
  152.             }
  153.         }
  154.  
  155.     sMemDisconnect( &stream );
  156.     return( status );
  157.     }
  158.  
  159. /* Export a general data object.  This currently doesn't support the full
  160.    capability of the data format:
  161.  
  162.    - Continuations aren't supported for any data types
  163.    - Only one hash algorithm type at a time is supported for SignedData
  164.      types */
  165.  
  166. CRET cryptExportObjectEx( void CPTR object, int CPTR objectLength,
  167.                           CRYPT_OBJECT_TYPE objectType, const long dataLength,
  168.                           const CRYPT_CONTEXT cryptContext )
  169.     {
  170.     CRYPT_INFO *cryptInfoPtr = CONTEXT_TO_INFO( cryptContext );
  171.     STREAM stream;
  172.     int status;
  173.  
  174.     /* Perform basic error checking */
  175.     if( objectType < CRYPT_OBJECT_ENCRYPTED_DATA || \
  176.         objectType > CRYPT_OBJECT_NONDATA )
  177.         return( CRYPT_BADPARM1 );
  178.     if( objectLength == NULL )
  179.         return( CRYPT_BADPARM2 );
  180.     if( objectType == CRYPT_OBJECT_ENCRYPTED_DATA || \
  181.         objectType == CRYPT_OBJECT_SIGNED_DATA )
  182.         {
  183.         if( isBadCookie( cryptContext ) || \
  184.             cryptInfoPtr->checkValue != CRYPT_MAGIC )
  185.             return( CRYPT_BADPARM3 );
  186.         if( objectType == CRYPT_OBJECT_ENCRYPTED_DATA &&
  187.             ( cryptInfoPtr->isPKCcontext || \
  188.               cryptInfoPtr->capabilityInfo->cryptMode == CRYPT_MODE_NONE ) )
  189.             return( CRYPT_BADPARM3 );
  190.         if( objectType == CRYPT_OBJECT_SIGNED_DATA && \
  191.             cryptInfoPtr->capabilityInfo->cryptMode != CRYPT_MODE_NONE )
  192.             return( CRYPT_BADPARM3 );
  193.         }
  194.     else
  195.         if( cryptContext != ( CRYPT_CONTEXT ) CRYPT_UNUSED )
  196.             return( CRYPT_BADPARM5 );
  197.     if( dataLength < 0 )
  198.         return( CRYPT_BADPARM4 );
  199.  
  200.     /* If it's compressed data, return with a bad parameter error (we don't
  201.        handle this data type yet) */
  202.     if( objectType == CRYPT_OBJECT_COMPRESSED_DATA )
  203.         return( CRYPT_BADPARM1 );
  204.  
  205.     /* Open a null or normal stream depending on whether we're just getting
  206.        the length or actually outputting data */
  207.     if( object == NULL )
  208.         sMemNullOpen( &stream );
  209.     else
  210.         sMemOpen( &stream, object, STREAMSIZE_UNKNOWN );
  211.  
  212.     /* If it's a basic data type, just write the data header */
  213.     if( objectType == CRYPT_OBJECT_RAW_DATA || \
  214.         objectType == CRYPT_OBJECT_NONDATA )
  215.         status = writeBasicObject( &stream, FALSE, dataLength,
  216.                                    objectType == CRYPT_OBJECT_RAW_DATA );
  217.  
  218.     /* If it's encrypted data, write the key cookie, IV, and data header */
  219.     if( objectType == CRYPT_OBJECT_ENCRYPTED_DATA )
  220.         {
  221.         /* If the algorithm requires an IV and there isn't already one
  222.            loaded, load one now.  This is somewhat nasty in that a side-
  223.            effect of calling cryptCreateDataObject() is to load an IV into
  224.            the encryption context, which isn't really part of the functions
  225.            job description.  However the alternative is to require the user
  226.            to either manually load an IV or to make at least one call to
  227.            cryptEncrypt() before calling cryptCreateDataObject(), which is
  228.            equally nasty.  The lesser of the two evils is to load the IV here
  229.            and assume that anyone messing with the low-level cryptLoadIV()
  230.            function will read the docs which warn about the side-effects of
  231.            cryptCreateDataObject() (anyone who needs to call cryptLoadIV()
  232.            probably won't be using the high-level object management functions
  233.            anyway) */
  234.         if( !cryptInfoPtr->ivSet )
  235.             {
  236.             BYTE iv[ CRYPT_MAX_IVSIZE ];
  237.             int status;
  238.  
  239.             getNonce( iv, cryptInfoPtr->ivLength );
  240.             if( ( status = loadIV( cryptInfoPtr, iv, cryptInfoPtr->ivLength ) ) != CRYPT_OK )
  241.                 return( status );
  242.             }
  243.  
  244.         /* Write the information to the stream */
  245.         status = writeEncryptedObject( &stream, FALSE, dataLength, cryptInfoPtr );
  246.         }
  247.  
  248.     /* If it's signed data, write the signature cookie, hash algorithm info,
  249.        and data header */
  250.     if( objectType == CRYPT_OBJECT_SIGNED_DATA )
  251.         status = writeSignedObject( &stream, FALSE, cryptInfoPtr, dataLength );
  252.  
  253.     *objectLength = sMemSize( &stream );
  254.  
  255.     sMemDisconnect( &stream );
  256.     return( status );
  257.     }
  258.  
  259. /* Import a general data object.  This currently doesn't support the full
  260.    capability of the data format:
  261.  
  262.    - Continuations aren't supported for any data types
  263.    - Only one hash algorithm type at a time is supported for SignedData types
  264.    - Checking of signature cookies isn't supported (it has to be done by
  265.      the user */
  266.  
  267. CRET cryptImportObjectEx( const void CPTR object, int CPTR payloadStart,
  268.                           long CPTR payloadLength,
  269.                           CRYPT_CONTEXT CPTR cryptContext )
  270.     {
  271.     CRYPT_INFO *cryptInfoPtr;
  272.     CRYPT_OBJECT_INFO cryptObjectInfo;
  273.     int status = CRYPT_OK;
  274.  
  275.     /* Perform basic error checking */
  276.     if( object == NULL )
  277.         return( CRYPT_BADPARM1 );
  278.     if( payloadStart == NULL )
  279.         return( CRYPT_BADPARM2 );
  280.     if( payloadLength == NULL )
  281.         return( CRYPT_BADPARM3 );
  282.     if( cryptContext == NULL )
  283.         return( CRYPT_BADPARM4 );
  284.  
  285.     /* Find out what sort of object we're dealing with */
  286.     status = cryptQueryObject( object, &cryptObjectInfo );
  287.     if( cryptStatusError( status ) )
  288.         return( status );
  289.     if( cryptObjectInfo.type == CRYPT_OBJECT_ENCRYPTED_DATA || \
  290.         cryptObjectInfo.type == CRYPT_OBJECT_SIGNED_DATA )
  291.         {
  292.         if( cryptContext == ( CRYPT_CONTEXT CPTR ) CRYPT_UNUSED )
  293.             return( CRYPT_BADPARM4 );
  294.  
  295.         cryptInfoPtr = CONTEXT_TO_INFO( *cryptContext );
  296.         if( cryptObjectInfo.type == CRYPT_OBJECT_ENCRYPTED_DATA && \
  297.             ( isBadCookie( *cryptContext ) || \
  298.               cryptInfoPtr->checkValue != CRYPT_MAGIC ) )
  299.             return( CRYPT_BADPARM4 );
  300.         }
  301.     else
  302.         if( cryptContext != ( CRYPT_CONTEXT CPTR ) CRYPT_UNUSED )
  303.             return( CRYPT_BADPARM4 );
  304.     *payloadStart = cryptObjectInfo.headerSize;
  305.     *payloadLength = cryptObjectInfo.payloadSize;
  306.  
  307.     /* If it's an encrypted data object, check the cookie and load the IV */
  308.     if( cryptObjectInfo.type == CRYPT_OBJECT_ENCRYPTED_DATA )
  309.         {
  310.         /* Make sure the encryption context is of the correct type */
  311.         if( cryptInfoPtr->isPKCcontext || \
  312.             cryptInfoPtr->capabilityInfo->cryptMode == CRYPT_MODE_NONE )
  313.             return( CRYPT_BADPARM2 );
  314.  
  315.         /* Check that we're using the correct decryption key */
  316.         if( cryptObjectInfo.cookieSize && \
  317.             memcmp( cryptInfoPtr->keyCookie, cryptObjectInfo.cookie,
  318.                     KEY_COOKIE_SIZE ) )
  319.             return( CRYPT_WRONGKEY );
  320.  
  321.         /* Load the IV from the encrypted data object */
  322.         if( needsIV( cryptInfoPtr->capabilityInfo->cryptMode ) )
  323.             status = loadIV( cryptInfoPtr, cryptObjectInfo.iv,
  324.                              cryptObjectInfo.ivSize );
  325.         }
  326.  
  327.     /* If it's a signed data object, create the hash context */
  328.     if( cryptObjectInfo.type == CRYPT_OBJECT_SIGNED_DATA )
  329.         {
  330.         /* The lower-level functions report back what algorithms were found,
  331.            but don't complain if they find unknown ones (the data may have
  332.            been created by a newer version of the library), so we check here
  333.            that a given algorithm is actually available, and that it's a
  334.            hash algorithm */
  335.         status = cryptModeAvailable( cryptObjectInfo.cryptAlgo,
  336.                                      CRYPT_MODE_NONE );
  337.         if( cryptStatusError( status ) )
  338.             return( status );
  339.  
  340.         /* Create the hash context.  If we get a parameter error for the
  341.            fourth parameter (a newer version of the library may add
  342.            parameters to existing algorithms) then we convert it to an no
  343.            algorithm error */
  344.         status = cryptCreateContextEx( cryptContext,
  345.                                        cryptObjectInfo.cryptAlgo,
  346.                                        CRYPT_MODE_NONE,
  347.                                        cryptObjectInfo.cryptContextExInfo );
  348.         if( status == CRYPT_BADPARM4 )
  349.             status = CRYPT_NOALGO;
  350.         }
  351.  
  352.     return( status );
  353.     }
  354.