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

  1. /****************************************************************************
  2. *                                                                            *
  3. *                          ASN.1 Key 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 "asn1keys.h"
  15.   #include "asn1objs.h"
  16.   #include "asn1oid.h"
  17. #else
  18.   #include "keymgmt/asn1.h"
  19.   #include "keymgmt/asn1keys.h"
  20.   #include "keymgmt/asn1objs.h"
  21.   #include "keymgmt/asn1oid.h"
  22. #endif /* Compiler-specific includes */
  23.  
  24. /* The restart marker used to identify the start of a key record */
  25.  
  26. #define RESTART_MARKER        ( BYTE * ) "\x0D\x0A\xA0\x00"
  27. #define RESTART_MARKER_SIZE    4
  28.  
  29. /****************************************************************************
  30. *                                                                            *
  31. *                                Utility Routines                            *
  32. *                                                                            *
  33. ****************************************************************************/
  34.  
  35. /* Context-specific tags for the public-key information record */
  36.  
  37. enum { CTAG_PK_VALIDFROM, CTAG_PK_VALIDTO };
  38.  
  39. /* Context-specific tags for the key collection header record */
  40.  
  41. enum { CTAG_KH_DESCRIPTION };
  42.  
  43. /* ASN.1's encoding rules always use the big-endian format, so we may need to
  44.    reverse the endianness before we read/write them */
  45.  
  46. static void byteReverse( BYTE *data, int count )
  47.     {
  48.     int sourceCount = 0;
  49.  
  50.     /* Swap endianness of data */
  51.     for( count--; count > sourceCount; count--, sourceCount++ )
  52.         {
  53.         BYTE temp;
  54.  
  55.         temp = data[ sourceCount ];
  56.         data[ sourceCount ] = data[ count ];
  57.         data[ count ] = temp;
  58.         }
  59.     }
  60.  
  61. /* Read/write a bignum with endianness conversion */
  62.  
  63. static int writeConvertStaticInteger( STREAM *stream, const BYTE *integer,
  64.                                       const int integerLength,
  65.                                       const int endianness )
  66.     {
  67.     /* If it's little-endian, make it big-endian before writing it */
  68.     if( endianness == CRYPT_COMPONENTS_LITTLENDIAN )
  69.         {
  70.         BYTE buffer[ CRYPT_MAX_PKCSIZE ];
  71.         int status;
  72.  
  73.         /* Endianess-reverse the integer and map the reversed data into a
  74.            temporary integer.  This sort of messing around with internal
  75.            integer values is rather naughty, but saves a mostly useless
  76.            malloc() */
  77.         memcpy( buffer, integer, integerLength );
  78.         byteReverse( buffer, integerLength );
  79.         status = writeStaticInteger( stream, buffer, integerLength, DEFAULT_TAG );
  80.         zeroise( buffer, CRYPT_MAX_PKCSIZE );
  81.  
  82.         return( status );
  83.         }
  84.  
  85.     /* It's big-endian already, output it as is */
  86.     return( writeStaticInteger( stream, integer, integerLength, DEFAULT_TAG ) );
  87.     }
  88.  
  89. static int readConvertStaticInteger( STREAM *stream, BYTE *integer,
  90.                                      int *integerLength, const int endianness )
  91.     {
  92.     int status;
  93.  
  94.     /* Read the value into a fixed buffer */
  95.     status = readStaticInteger( stream, integer, integerLength, CRYPT_MAX_PKCSIZE );
  96.  
  97.     /* If it's meant to be little-endian, convert it */
  98.     if( endianness == CRYPT_COMPONENTS_LITTLENDIAN )
  99.         byteReverse( integer, *integerLength );
  100.  
  101.     return( status );
  102.     }
  103.  
  104. /* Read the DH public key components */
  105.  
  106. static int readDHcomponents( STREAM *stream, CRYPT_PKCINFO_DH *dhKey )
  107.     {
  108.     int readDataLength, length;
  109.     long dummy;
  110.  
  111.     /* Read start of public-key info sequence fields */
  112.     if( readTag( stream ) != BER_SEQUENCE )
  113.         {
  114.         sSetError( stream, STREAM_BADDATA );
  115.         return( CRYPT_BADDATA );
  116.         }
  117.     readDataLength = readLength( stream, &dummy ) + 1;    /* Skip SEQ len.*/
  118.  
  119.     /* Read the key components */
  120.     readDataLength += readConvertStaticInteger( stream, dhKey->p, &length, dhKey->endianness );
  121.     dhKey->pLen = bytesToBits( length );
  122.     readDataLength += readConvertStaticInteger( stream, dhKey->g, &length, dhKey->endianness );
  123.     dhKey->gLen = bytesToBits( length );
  124.  
  125.     if( sGetStatus( stream ) != STREAM_OK )
  126.         return( sGetStatus( stream ) );
  127.     return( readDataLength );
  128.     }
  129.  
  130. /* Write the DH public key components */
  131.  
  132. static void writeDHcomponents( STREAM *stream,
  133.                                const CRYPT_PKCINFO_DH *dhKey )
  134.     {
  135.     /* Write the identifier and length fields */
  136.     writeTag( stream, BER_SEQUENCE );
  137.     writeLength( stream, sizeofObject( bitsToBytes( dhKey->pLen ) ) +
  138.                  sizeofObject( bitsToBytes( dhKey->gLen ) ) );
  139.  
  140.     /* Write the the PKC fields */
  141.     writeConvertStaticInteger( stream, dhKey->p, bitsToBytes( dhKey->pLen ),
  142.                                dhKey->endianness );
  143.     writeConvertStaticInteger( stream, dhKey->g, bitsToBytes( dhKey->gLen ),
  144.                                dhKey->endianness );
  145.     }
  146.  
  147. /* Read the RSA public or private key components */
  148.  
  149. static int readRSAcomponents( STREAM *stream, CRYPT_PKCINFO_RSA *rsaKey,
  150.                               const BOOLEAN isPublicKey )
  151.     {
  152.     int readDataLength, length;
  153.     long dummy;
  154.  
  155.     /* Read start of public-key info sequence fields */
  156.     if( readTag( stream ) != BER_SEQUENCE )
  157.         {
  158.         sSetError( stream, STREAM_BADDATA );
  159.         return( CRYPT_BADDATA );
  160.         }
  161.     readDataLength = readLength( stream, &dummy ) + 1;    /* Skip SEQ len.*/
  162.  
  163.     /* Read the key components */
  164.     if( !isPublicKey )
  165.         /* Ignored, present for PKCS compatibility only */
  166.         readDataLength += readShortInteger( stream, &dummy );
  167.     readDataLength += readConvertStaticInteger( stream, rsaKey->n, &length, rsaKey->endianness );
  168.     rsaKey->nLen = bytesToBits( length );
  169.     readDataLength += readConvertStaticInteger( stream, rsaKey->e, &length, rsaKey->endianness );
  170.     rsaKey->eLen = bytesToBits( length );
  171.     if( !isPublicKey )
  172.         {
  173.         readDataLength += readConvertStaticInteger( stream, rsaKey->d, &length, rsaKey->endianness );
  174.         rsaKey->dLen = bytesToBits( length );
  175.         readDataLength += readConvertStaticInteger( stream, rsaKey->p, &length, rsaKey->endianness );
  176.         rsaKey->pLen = bytesToBits( length );
  177.         readDataLength += readConvertStaticInteger( stream, rsaKey->q, &length, rsaKey->endianness );
  178.         rsaKey->qLen = bytesToBits( length );
  179.         readDataLength += readConvertStaticInteger( stream, rsaKey->e1, &length, rsaKey->endianness );
  180.         rsaKey->e1Len = bytesToBits( length );
  181.         readDataLength += readConvertStaticInteger( stream, rsaKey->e2, &length, rsaKey->endianness );
  182.         rsaKey->e2Len = bytesToBits( length );
  183.         readDataLength += readConvertStaticInteger( stream, rsaKey->u, &length, rsaKey->endianness );
  184.         rsaKey->uLen = bytesToBits( length );
  185.         }
  186.  
  187.     if( sGetStatus( stream ) != STREAM_OK )
  188.         return( sGetStatus( stream ) );
  189.     return( readDataLength );
  190.     }
  191.  
  192. /* Write the RSA public or private key components */
  193.  
  194. static void writeRSAcomponents( STREAM *stream,
  195.                                 const CRYPT_PKCINFO_RSA *rsaKey )
  196.     {
  197.     BOOLEAN isPublicKey = rsaKey->isPublicKey;
  198.     long size = 0;
  199.  
  200.     /* Determine the size of the private fields */
  201.     if( !isPublicKey )
  202.         size = sizeofEnumerated( 0 ) +
  203.                sizeofObject( bitsToBytes( rsaKey->dLen ) ) +
  204.                sizeofObject( bitsToBytes( rsaKey->pLen ) ) +
  205.                sizeofObject( bitsToBytes( rsaKey->qLen ) ) +
  206.                sizeofObject( bitsToBytes( rsaKey->e1Len ) ) +
  207.                sizeofObject( bitsToBytes( rsaKey->e2Len ) ) +
  208.                sizeofObject( bitsToBytes( rsaKey->uLen ) );
  209.  
  210.     /* Write the identifier and length fields */
  211.     writeTag( stream, BER_SEQUENCE );
  212.     writeLength( stream, sizeofObject( bitsToBytes( rsaKey->nLen ) ) +
  213.                  sizeofObject( bitsToBytes( rsaKey->eLen ) ) + size );
  214.  
  215.     /* Write the the PKC fields */
  216.     if( !isPublicKey )
  217.         writeEnumerated( stream, 0, DEFAULT_TAG );    /* For PKCS compatibility */
  218.     writeConvertStaticInteger( stream, rsaKey->n, bitsToBytes( rsaKey->nLen ),
  219.                                rsaKey->endianness );
  220.     writeConvertStaticInteger( stream, rsaKey->e, bitsToBytes( rsaKey->eLen ),
  221.                                rsaKey->endianness );
  222.     if( !isPublicKey )
  223.         {
  224.         writeConvertStaticInteger( stream, rsaKey->d, bitsToBytes( rsaKey->dLen ),
  225.                                    rsaKey->endianness );
  226.         writeConvertStaticInteger( stream, rsaKey->p, bitsToBytes( rsaKey->pLen ),
  227.                                    rsaKey->endianness );
  228.         writeConvertStaticInteger( stream, rsaKey->q, bitsToBytes( rsaKey->qLen ),
  229.                                    rsaKey->endianness );
  230.         writeConvertStaticInteger( stream, rsaKey->e1, bitsToBytes( rsaKey->e1Len ),
  231.                                    rsaKey->endianness );
  232.         writeConvertStaticInteger( stream, rsaKey->e2, bitsToBytes( rsaKey->e2Len ),
  233.                                    rsaKey->endianness );
  234.         writeConvertStaticInteger( stream, rsaKey->u, bitsToBytes( rsaKey->uLen ),
  235.                                    rsaKey->endianness );
  236.         }
  237.     }
  238.  
  239. /* Read the DSA public or private key components */
  240.  
  241. static int readDSAcomponents( STREAM *stream, CRYPT_PKCINFO_DSA *dsaKey,
  242.                               const BOOLEAN isPublicKey )
  243.     {
  244.     int readDataLength = 0, length;
  245.     long dummy;
  246.  
  247.     /* Read start of public-key info sequence fields */
  248.     if( readTag( stream ) != BER_SEQUENCE )
  249.         {
  250.         sSetError( stream, STREAM_BADDATA );
  251.         return( CRYPT_BADDATA );
  252.         }
  253.     readDataLength += readLength( stream, &dummy ) + 1;    /* Skip SEQ len.*/
  254.  
  255.     /* Read the key components */
  256.     if( !isPublicKey )
  257.         /* Ignored, present for PKCS compatibility only */
  258.         readDataLength += readEnumerated( stream, &length );
  259.     readDataLength += readConvertStaticInteger( stream, dsaKey->p, &length, dsaKey->endianness );
  260.     dsaKey->pLen = bytesToBits( length );
  261.     readDataLength += readConvertStaticInteger( stream, dsaKey->q, &length, dsaKey->endianness );
  262.     dsaKey->qLen = bytesToBits( length );
  263.     readDataLength += readConvertStaticInteger( stream, dsaKey->x, &length, dsaKey->endianness );
  264.     dsaKey->xLen = bytesToBits( length );
  265.     if( !isPublicKey )
  266.         {
  267.         readDataLength += readConvertStaticInteger( stream, dsaKey->y, &length, dsaKey->endianness );
  268.         dsaKey->yLen = bytesToBits( length );
  269.         }
  270.  
  271.     if( sGetStatus( stream ) != STREAM_OK )
  272.         return( sGetStatus( stream ) );
  273.     return( readDataLength );
  274.     }
  275.  
  276. /* Write the DSA public or private key components */
  277.  
  278. static void writeDSAcomponents( STREAM *stream,
  279.                                 const CRYPT_PKCINFO_DSA *dsaKey )
  280.     {
  281.     BOOLEAN isPublicKey = dsaKey->isPublicKey;
  282.     long size = 0;
  283.  
  284.     /* Determine the size of the private fields */
  285.     if( !isPublicKey )
  286.         size = sizeofEnumerated( 0 ) +
  287.                sizeofObject( bitsToBytes( dsaKey->yLen ) ) +
  288.  
  289.     /* Write the identifier and length fields */
  290.     writeTag( stream, BER_SEQUENCE );
  291.     writeLength( stream, sizeofObject( bitsToBytes( dsaKey->pLen ) ) +
  292.                  sizeofObject( bitsToBytes( dsaKey->qLen ) ) +
  293.                  sizeofObject( bitsToBytes( dsaKey->xLen ) ) + size );
  294.  
  295.     /* Write the the PKC fields */
  296.     if( !isPublicKey )
  297.         writeEnumerated( stream, 0, DEFAULT_TAG );    /* For PKCS compatibility */
  298.     writeConvertStaticInteger( stream, dsaKey->p, bitsToBytes( dsaKey->pLen ),
  299.                                dsaKey->endianness );
  300.     writeConvertStaticInteger( stream, dsaKey->q, bitsToBytes( dsaKey->qLen ),
  301.                                dsaKey->endianness );
  302.     writeConvertStaticInteger( stream, dsaKey->x, bitsToBytes( dsaKey->xLen ),
  303.                                dsaKey->endianness );
  304.     if( !isPublicKey )
  305.         writeConvertStaticInteger( stream, dsaKey->y, bitsToBytes( dsaKey->yLen ),
  306.                                    dsaKey->endianness );
  307.     }
  308.  
  309. /* Generate a key ID */
  310.  
  311. int generateKeyID( CRYPT_ALGO algorithm, BYTE *keyID, int *keyIDlength,
  312.                    void *pkcInfo )
  313.     {
  314.     STREAM stream;
  315.     MESSAGE_DIGEST mdKeyID;
  316.     BYTE buffer[ ( CRYPT_MAX_PKCSIZE * 2 ) + 50 ];
  317.     BYTE hashResult[ CRYPT_MAX_HASHSIZE ];
  318.     int isPublicKey;
  319.     int hashAlgorithm, hashInfoSize, hashInputSize, hashOutputSize;
  320.     HASHFUNCTION hashFunction;
  321.  
  322.     /* The following define makes the code to access the public-key flag in
  323.        various structures slightly less ugly */
  324.     #define pubkeyField( pointer, type )    ( ( type * ) pointer )->isPublicKey
  325.  
  326.     /* Get the hash algorithm information */
  327.     hashAlgorithm = CRYPT_ALGO_SHA;        /* Always use SHA for now */
  328.     if( !getHashParameters( hashAlgorithm, &hashFunction, &hashInputSize,
  329.                             &hashOutputSize, &hashInfoSize ) )
  330.         return( CRYPT_ERROR );    /* API error, should never occur */
  331.  
  332.     /* Write the public key fields to a buffer.  We cheat a bit here in that
  333.        we know the memory stream is connected to the buffer, so we don't
  334.        bother reading it out into a temporary buffer.  Since the key we've
  335.        been passed might be a private or public key, we need to fool the
  336.        write function into only writing the public fields, so we make it look
  337.        like a public key while it's being written */
  338.     sMemOpen( &stream, buffer, ( CRYPT_MAX_PKCSIZE * 2 ) + 50 );
  339.     switch( algorithm )
  340.         {
  341.         case CRYPT_ALGO_DH:
  342.             isPublicKey = pubkeyField( pkcInfo, CRYPT_PKCINFO_DH );
  343.             pubkeyField( pkcInfo, CRYPT_PKCINFO_DH ) = TRUE;
  344.             writeDHcomponents( &stream, ( CRYPT_PKCINFO_DH * ) pkcInfo );
  345.             pubkeyField( pkcInfo, CRYPT_PKCINFO_DH ) = isPublicKey;
  346.             break;
  347.  
  348.         case CRYPT_ALGO_RSA:
  349.             isPublicKey = pubkeyField( pkcInfo, CRYPT_PKCINFO_RSA );
  350.             pubkeyField( pkcInfo, CRYPT_PKCINFO_RSA ) = TRUE;
  351.             writeRSAcomponents( &stream, ( CRYPT_PKCINFO_RSA * ) pkcInfo );
  352.             pubkeyField( pkcInfo, CRYPT_PKCINFO_RSA ) = isPublicKey;
  353.             break;
  354.  
  355.         case CRYPT_ALGO_DSA:
  356.             isPublicKey = pubkeyField( pkcInfo, CRYPT_PKCINFO_DSA );
  357.             pubkeyField( pkcInfo, CRYPT_PKCINFO_DSA ) = TRUE;
  358.             writeDSAcomponents( &stream, ( CRYPT_PKCINFO_DSA * ) pkcInfo );
  359.             pubkeyField( pkcInfo, CRYPT_PKCINFO_DSA ) = isPublicKey;
  360.             break;
  361.  
  362.         default:
  363.             return( CRYPT_ERROR );    /* Internal error, should never happen */
  364.         }
  365.     if( sGetStatus( &stream ) != STREAM_OK )
  366.         return( CRYPT_ERROR );        /* Internal error, should never happen */
  367.  
  368.     /* Hash the DER-encoded public key fields to get the key ID */
  369.     hashFunction( NULL, hashResult, buffer, sMemSize( &stream ), HASH_ALL );
  370.     sMemClose( &stream );
  371.  
  372.     /* Write the key ID (in encoded format) to the key ID buffer */
  373.     sMemOpen( &stream, keyID, CRYPT_MAX_KEYIDSIZE );
  374.     newMessageDigest( &mdKeyID, hashAlgorithm, hashResult, hashOutputSize );
  375.     writeMessageDigest( &stream, &mdKeyID, DEFAULT_TAG );
  376.     deleteMessageDigest( &mdKeyID );
  377.     *keyIDlength = sMemSize( &stream );
  378.     sMemDisconnect( &stream );
  379.  
  380.     return( CRYPT_OK );
  381.     }
  382.  
  383. /****************************************************************************
  384. *                                                                            *
  385. *                        sizeof() methods for ASN.1 Types                    *
  386. *                                                                            *
  387. ****************************************************************************/
  388.  
  389. /* Determine the size of an AlgorithmIdentifier record */
  390.  
  391. static int sizeofAlgorithmIdentifier( const PKC_INFO *pkcInfo )
  392.     {
  393.     int size = sizeof( BYTE ) + sizeof( BYTE ) + sizeofNull();
  394.  
  395.     /* Add the size of the AlgorithmIdentifier record */
  396.     switch( pkcInfo->algorithm )
  397.         {
  398.         case CRYPT_ALGO_DH:
  399.             return( size + sizeofOID( OID_DHKEYAGREEMENT ) );
  400.  
  401.         case CRYPT_ALGO_RSA:
  402.             return( size + sizeofOID( OID_RSAENCRYPTION ) );
  403.  
  404.         case CRYPT_ALGO_DSA:
  405.             return( size + sizeofOID( OID_DSAENCRYPTION ) );
  406.         }
  407.  
  408.     return( CRYPT_ERROR );    /* Internal error, should never happen */
  409.     }
  410.  
  411. /* Determine the size of the DH public key components */
  412.  
  413. static int sizeofDHcomponents( const CRYPT_PKCINFO_DH *dhKey )
  414.     {
  415.     long size;
  416.  
  417.     size = sizeofObject( bitsToBytes( dhKey->pLen ) ) +
  418.            sizeofObject( bitsToBytes( dhKey->gLen ) );
  419.  
  420.     return( sizeof( BYTE ) + calculateLengthSize( size ) + ( int ) size );
  421.     }
  422.  
  423. /* Determine the size of the RSA public or private key components */
  424.  
  425. static int sizeofRSAcomponents( const CRYPT_PKCINFO_RSA *rsaKey )
  426.     {
  427.     long size;
  428.  
  429.     size = sizeofObject( bitsToBytes( rsaKey->nLen ) ) +
  430.            sizeofObject( bitsToBytes( rsaKey->eLen ) );
  431.     if( !rsaKey->isPublicKey )
  432.         size += sizeofEnumerated( 0 ) +
  433.                 sizeofObject( bitsToBytes( rsaKey->dLen ) ) +
  434.                 sizeofObject( bitsToBytes( rsaKey->pLen ) ) +
  435.                 sizeofObject( bitsToBytes( rsaKey->qLen ) ) +
  436.                 sizeofObject( bitsToBytes( rsaKey->e1Len ) ) +
  437.                 sizeofObject( bitsToBytes( rsaKey->e2Len ) ) +
  438.                 sizeofObject( bitsToBytes( rsaKey->uLen ) );
  439.  
  440.     return( sizeof( BYTE ) + calculateLengthSize( size ) + ( int ) size );
  441.     }
  442.  
  443. /* Determine the size of the DSA public or private key components */
  444.  
  445. static int sizeofDSAcomponents( const CRYPT_PKCINFO_DSA *dsaKey )
  446.     {
  447.     long size;
  448.  
  449.     size = sizeofObject( bitsToBytes( dsaKey->pLen ) ) +
  450.            sizeofObject( bitsToBytes( dsaKey->qLen ) ) +
  451.            sizeofObject( bitsToBytes( dsaKey->xLen ) );
  452.     if( !dsaKey->isPublicKey )
  453.         size += sizeofEnumerated( 0 ) +
  454.                 sizeofObject( bitsToBytes( dsaKey->yLen ) );
  455.  
  456.     return( sizeof( BYTE ) + calculateLengthSize( size ) + ( int ) size );
  457.     }
  458.  
  459. /* Determine the size of the data payload of an X.509 SubjectPublicKeyInfo
  460.    record (not including the SEQUENCE encapsulation) */
  461.  
  462. static int sizeofPublicKeyData( const PKC_INFO *pkcInfo )
  463.     {
  464.     int size;
  465.  
  466.     /* Determine the size of the PKC information */
  467.     switch( pkcInfo->algorithm )
  468.         {
  469.         case CRYPT_ALGO_DH:
  470.             size = sizeofDHcomponents( ( CRYPT_PKCINFO_DH * ) pkcInfo->keyInfo );
  471.             break;
  472.  
  473.         case CRYPT_ALGO_RSA:
  474.             size = sizeofRSAcomponents( ( CRYPT_PKCINFO_RSA * ) pkcInfo->keyInfo );
  475.             break;
  476.  
  477.         case CRYPT_ALGO_DSA:
  478.             size = sizeofDSAcomponents( ( CRYPT_PKCINFO_DSA * ) pkcInfo->keyInfo );
  479.             break;
  480.  
  481.         default:
  482.             return( CRYPT_ERROR );    /* Internal error, should never happen */
  483.         }
  484.  
  485.     /* Return the size of the AlgorithmIdentifier record and the BITSTRING-
  486.        encapsulated public-key data */
  487.     return( sizeofAlgorithmIdentifier( pkcInfo ) + sizeof( BYTE ) +
  488.             calculateLengthSize( size ) + size );
  489.     }
  490.  
  491. /****************************************************************************
  492. *                                                                            *
  493. *                            Read/Write X.509 Key Records                    *
  494. *                                                                            *
  495. ****************************************************************************/
  496.  
  497. /* Read a public key from an X.509 SubjectPublicKeyInfo record */
  498.  
  499. int readPublicKey( STREAM *stream, PKC_INFO *pkcInfo )
  500.     {
  501.     BYTE buffer[ MAX_OID_SIZE ];
  502.     int readDataLength, totalLength, bufferLength;
  503.     long length;
  504.  
  505.     /* Clear the return data in case we don't get anything useful */
  506.     memset( pkcInfo, 0, sizeof( PKC_INFO ) );
  507.  
  508.     /* Read the SubjectPublicKeyInfo header field */
  509.     if( readTag( stream ) != BER_SEQUENCE )
  510.         return( CRYPT_BADDATA );
  511.     readDataLength = readLength( stream, &length ) + 1;
  512.     totalLength = ( int ) length + readDataLength;
  513.  
  514.     /* Read the AlgorithmIdentifier header */
  515.     if( readTag( stream ) != BER_SEQUENCE )
  516.         return( CRYPT_BADDATA );
  517.     readDataLength += readLength( stream, &length ) + 1;
  518.  
  519.     /* Determine the key type based on the AlgorithmIdentifier field */
  520.     readDataLength += readRawObject( stream, buffer, &bufferLength,
  521.                                      MAX_OID_SIZE, BER_OBJECT_IDENTIFIER );
  522.     if( !memcmp( buffer, OID_DHKEYAGREEMENT, bufferLength ) )
  523.         {
  524.         pkcInfo->algorithm = CRYPT_ALGO_DH;
  525.         pkcInfo->keyInfoSize = sizeof( CRYPT_PKCINFO_RSA );
  526.         }
  527.     if( !memcmp( buffer, OID_RSAENCRYPTION, bufferLength ) )
  528.         {
  529.         pkcInfo->algorithm = CRYPT_ALGO_RSA;
  530.         pkcInfo->keyInfoSize = sizeof( CRYPT_PKCINFO_RSA );
  531.         }
  532.     if( !memcmp( buffer, OID_DSAENCRYPTION, bufferLength ) )
  533.         {
  534.         pkcInfo->algorithm = CRYPT_ALGO_DSA;
  535.         pkcInfo->keyInfoSize = sizeof( CRYPT_PKCINFO_RSA );
  536.         }
  537.     if( pkcInfo->algorithm == CRYPT_ALGO_NONE )
  538.         {
  539.         /* Unknown algorithm type, return */
  540.         sSkip( stream, totalLength - readDataLength );
  541.         return( CRYPT_NOALGO );
  542.         }
  543.     /* Read the BITSTRING encapsulation of the public key fields */
  544.     if( readTag( stream ) != BER_BITSTRING )
  545.         return( CRYPT_BADDATA );
  546.     readLength( stream, &length );
  547.     sgetc( stream );    /* Skip extra bit count in bitfield */
  548.  
  549.     /* Finally, read the PKC information and generate the key ID for it */
  550.     if( ( pkcInfo->keyInfo = malloc( pkcInfo->keyInfoSize ) ) == NULL )
  551.         return( CRYPT_NOMEM );
  552.     switch( pkcInfo->algorithm )
  553.         {
  554.         case CRYPT_ALGO_DH:
  555.             readDataLength += readDHcomponents( stream,
  556.                         ( CRYPT_PKCINFO_DH * ) pkcInfo->keyInfo );
  557.             break;
  558.  
  559.         case CRYPT_ALGO_RSA:
  560.             readDataLength += readRSAcomponents( stream,
  561.                         ( CRYPT_PKCINFO_RSA * ) pkcInfo->keyInfo, TRUE );
  562.             break;
  563.  
  564.         case CRYPT_ALGO_DSA:
  565.             readDataLength += readDSAcomponents( stream,
  566.                         ( CRYPT_PKCINFO_DSA * ) pkcInfo->keyInfo, TRUE );
  567.             break;
  568.  
  569.         default:
  570.             return( CRYPT_ERROR );    /* Internal error, should never happen */
  571.         }
  572.  
  573.     if( sGetStatus( stream ) != STREAM_OK )
  574.         {
  575.         zeroise( pkcInfo->keyInfo, pkcInfo->keyInfoSize );
  576.         free( pkcInfo->keyInfo );
  577.         zeroise( pkcInfo, sizeof( PKC_INFO ) );
  578.         return( CRYPT_BADDATA );
  579.         }
  580.     return( readDataLength );
  581.     }
  582.  
  583. /* Write a public key to an X.509 SubjectPublicKeyInfo record */
  584.  
  585. int writePublicKey( STREAM *stream, const PKC_INFO *pkcInfo )
  586.     {
  587.     /* Write the SubjectPublicKeyInfo header field */
  588.     writeTag( stream, BER_SEQUENCE );
  589.     writeLength( stream, sizeofPublicKeyData( pkcInfo ) );
  590.  
  591.     /* Write the AlgorithmIdentifier field.  The type and length will
  592.        always be encoded as two bytes so we use sizeofAlgorithmIdentifier()
  593.        and subtract the size of the header for the length */
  594.     writeTag( stream, BER_SEQUENCE );
  595.     writeLength( stream, sizeofAlgorithmIdentifier( pkcInfo ) -
  596.                  sizeof( BYTE ) + sizeof( BYTE ) );
  597.     switch( pkcInfo->algorithm )
  598.         {
  599.         case CRYPT_ALGO_DH:
  600.             swrite( stream, OID_DHKEYAGREEMENT, sizeofOID( OID_DHKEYAGREEMENT ) );
  601.             break;
  602.  
  603.         case CRYPT_ALGO_RSA:
  604.             swrite( stream, OID_RSAENCRYPTION, sizeofOID( OID_RSAENCRYPTION ) );
  605.             break;
  606.  
  607.         case CRYPT_ALGO_DSA:
  608.             swrite( stream, OID_DSAENCRYPTION, sizeofOID( OID_DSAENCRYPTION ) );
  609.             break;
  610.  
  611.         default:
  612.             return( CRYPT_ERROR );    /* Internal error, should never happen */
  613.         }
  614.  
  615.     /* Write the BITSTRING wrapper for the PKC information */
  616.     writeTag( stream, BER_SEQUENCE );
  617.     switch( pkcInfo->algorithm )
  618.         {
  619.         case CRYPT_ALGO_DH:
  620.             writeLength( stream, sizeofDHcomponents( ( CRYPT_PKCINFO_DH * ) \
  621.                          pkcInfo->keyInfo ) );
  622.             break;
  623.  
  624.         case CRYPT_ALGO_RSA:
  625.             writeLength( stream, sizeofRSAcomponents( ( CRYPT_PKCINFO_RSA * ) \
  626.                          pkcInfo->keyInfo ) );
  627.             break;
  628.  
  629.         case CRYPT_ALGO_DSA:
  630.             writeLength( stream, sizeofDSAcomponents( ( CRYPT_PKCINFO_DSA * ) \
  631.                          pkcInfo->keyInfo ) );
  632.             break;
  633.  
  634.         default:
  635.             return( CRYPT_ERROR );    /* Internal error, should never happen */
  636.         }
  637.  
  638.     /* Finally, write the PKC information */
  639.     switch( pkcInfo->algorithm )
  640.         {
  641.         case CRYPT_ALGO_DH:
  642.             writeDHcomponents( stream, ( CRYPT_PKCINFO_DH * ) \
  643.                                pkcInfo->keyInfo );
  644.             break;
  645.  
  646.         case CRYPT_ALGO_RSA:
  647.             writeRSAcomponents( stream, ( CRYPT_PKCINFO_RSA * ) \
  648.                                 pkcInfo->keyInfo );
  649.             break;
  650.  
  651.         case CRYPT_ALGO_DSA:
  652.             writeDSAcomponents( stream, ( CRYPT_PKCINFO_DSA * ) \
  653.                                 pkcInfo->keyInfo );
  654.             break;
  655.  
  656.         default:
  657.             return( CRYPT_ERROR );    /* Internal error, should never happen */
  658.         }
  659.  
  660.     return( sGetStatus( stream ) );
  661.     }
  662.  
  663. /****************************************************************************
  664. *                                                                            *
  665. *                    Read/Write Key Collection/Record Headers                *
  666. *                                                                            *
  667. ****************************************************************************/
  668.  
  669. #ifdef FULL_KEYMGMT
  670.  
  671. /* Read a key collection header record */
  672.  
  673. int _readHeader( STREAM *stream, int *noRecords, int *maxVersion,
  674.                  char *description, const BOOLEAN readIdent )
  675.     {
  676.     int readDataLength = 0, dataLength, tagLength;
  677.     long length;
  678.  
  679.     /* Read the identifier field if necessary */
  680.     if( readIdent )
  681.         {
  682.         if( readTag( stream ) != BER_SEQUENCE )
  683.             {
  684.             sSetError( stream, STREAM_BADDATA );
  685.             return( CRYPT_BADDATA );
  686.             }
  687.         readDataLength++;
  688.         }
  689.     readDataLength += readLength( stream, &length );
  690.  
  691.     /* Read the various components */
  692.     dataLength = readShortInteger( stream, ( long * ) noRecords );
  693.     dataLength += readShortInteger( stream, ( long * ) maxVersion );
  694.     tagLength = checkReadCtag( stream, CTAG_KH_DESCRIPTION, TRUE );
  695.     if( tagLength )
  696.         dataLength += readStaticTextString( stream, description,
  697.                                     CRYPT_MAX_TEXTSIZE, FALSE ) + tagLength;
  698.  
  699.     /* Read any extra fields which might be present */
  700.     if( dataLength < length )
  701.         {
  702.         int remainder = ( int ) length - dataLength;
  703.  
  704.         sSkip( stream, remainder );
  705.         dataLength += remainder;
  706.         }
  707.  
  708.     if( *noRecords < 1 || *maxVersion < 0 )
  709.         return( CRYPT_BADDATA );
  710.     if( sGetStatus( stream ) != STREAM_OK )
  711.         return( sGetStatus( stream ) );
  712.     return( readDataLength + dataLength );
  713.     }
  714.  
  715. /* Write a key collection header record */
  716.  
  717. int writeHeader( STREAM *stream, const int noRecords, const int maxVersion,
  718.                  const char *description, const int tag )
  719.     {
  720.     int size = 0;
  721.  
  722.     /* If there's a description for this key collection, evaluate the size
  723.        of the encoded string */
  724.     if( description != NULL )
  725.         size += sizeofTextString( description );
  726.  
  727.     /* Write the identifier and length fields */
  728.     if( tag == DEFAULT_TAG )
  729.         writeTag( stream, BER_SEQUENCE );
  730.     else
  731.         writeCtag( stream, tag, TRUE );
  732.     writeLength( stream, sizeofShortInteger( noRecords ) +
  733.                  sizeofShortInteger( maxVersion ) + size );
  734.  
  735.     /* It's a composite type.  Write the various fields */
  736.     writeShortInteger( stream, noRecords, DEFAULT_TAG );
  737.     writeShortInteger( stream, maxVersion, DEFAULT_TAG );
  738.     if( description != NULL )
  739.         writeTextString( stream, description, CTAG_KH_DESCRIPTION );
  740.  
  741.     return( sGetStatus( stream ) );
  742.     }
  743.  
  744. /* Read a key record header */
  745.  
  746. int _readKeyRecordHeader( STREAM *stream, int *length, const BOOLEAN readIdent )
  747.     {
  748.     int readDataLength = 0, size, markerLength;
  749.     long longLength;
  750.     BYTE buffer[ 5 ];
  751.  
  752.     /* Read the identifier field if necessary */
  753.     if( readIdent )
  754.         {
  755.         if( readTag( stream ) != BER_SEQUENCE )
  756.             {
  757.             sSetError( stream, STREAM_BADDATA );
  758.             return( CRYPT_BADDATA );
  759.             }
  760.         readDataLength++;
  761.         }
  762.     readDataLength += readLength( stream, &longLength );
  763.     *length = ( int ) longLength;
  764.  
  765.     /* Read and check the restart marker */
  766.     markerLength = readStaticOctetString( stream, buffer, &size,
  767.                                           RESTART_MARKER_SIZE );
  768.     if( memcmp( buffer, RESTART_MARKER, size ) )
  769.         {
  770.         sSetError( stream, STREAM_BADDATA );
  771.         return( CRYPT_BADDATA );
  772.         }
  773.     *length -= markerLength;
  774.  
  775.     if( sGetStatus( stream ) != STREAM_OK )
  776.         return( sGetStatus( stream ) );
  777.     return( readDataLength + markerLength );
  778.     }
  779.  
  780. /* Write a key record header */
  781.  
  782. int writeKeyRecordHeader( STREAM *stream, int length, const int tag )
  783.     {
  784.     /* Write the identifier and length fields */
  785.     if( tag == DEFAULT_TAG )
  786.         writeTag( stream, BER_SEQUENCE );
  787.     else
  788.         writeCtag( stream, tag, TRUE );
  789.     writeLength( stream, ( int ) sizeofObject( RESTART_MARKER_SIZE ) + length );
  790.  
  791.     /* Write the restart marker */
  792.     writeByteString( stream, RESTART_MARKER, RESTART_MARKER_SIZE, DEFAULT_TAG );
  793.  
  794.     return( sGetStatus( stream ) );
  795.     }
  796.  
  797. /****************************************************************************
  798. *                                                                            *
  799. *                            Read/Write Key Record                             *
  800. *                                                                            *
  801. ****************************************************************************/
  802.  
  803. /* Read the start of a generic public or private key record */
  804.  
  805. static int readKeyHeader( STREAM *stream, PKC_INFO *pkcInfo, int *length,
  806.                           const BOOLEAN readIdent )
  807.     {
  808.     KEYID *keyIDptr = &pkcInfo->keyID;
  809.     MESSAGE_DIGEST keyID;
  810.     TIME validFrom, validTo;
  811.     int readDataLength = 0, dataLength, tagLength;
  812.     long longLength;
  813.  
  814.     /* Read the identifier field if necessary */
  815.     if( readIdent )
  816.         {
  817.         if( readTag( stream ) != BER_SEQUENCE )
  818.             {
  819.             sSetError( stream, STREAM_BADDATA );
  820.             return( CRYPT_BADDATA );
  821.             }
  822.         readDataLength++;
  823.         }
  824.  
  825.     /* Read key ID and validity period */
  826.     readDataLength += readLength( stream, &longLength );
  827.     *length = ( int ) longLength;
  828.     dataLength = readMessageDigest( stream, &keyID );
  829.     keyIDptr->hashAlgo = keyID.type;
  830.     keyIDptr->keyIDlength = keyID.length;
  831.     memcpy( keyIDptr->keyID, keyID.data, keyID.length );
  832.     deleteMessageDigest( &keyID );
  833.     newTime( &validFrom, 0, 0 );
  834.     newTime( &validTo, 0, 0 );
  835.     tagLength = checkReadCtag( stream, CTAG_PK_VALIDFROM, TRUE );
  836.     if( tagLength )
  837.         dataLength += readTimeData( stream, &validFrom ) + tagLength;
  838.     tagLength = checkReadCtag( stream, CTAG_PK_VALIDTO, TRUE );
  839.     if( tagLength )
  840.         dataLength += readTimeData( stream, &validTo ) + tagLength;
  841.     dataLength += readEnumerated( stream, ( int * ) &pkcInfo->algorithm );
  842.     pkcInfo->validFrom = validFrom.seconds;
  843.     pkcInfo->validTo = validTo.seconds;
  844.     deleteTime( &validFrom );
  845.     deleteTime( &validTo );
  846.     *length -= dataLength;
  847.  
  848.     /* Since this is an internal routine there's no need for an error check
  849.        at this point */
  850.     return( readDataLength + dataLength );
  851.     }
  852.  
  853. /* Write the start of a generic public or private key record */
  854.  
  855. static int writeKeyHeader( STREAM *stream, const int tag, PKC_INFO *pkcInfo )
  856.     {
  857.     KEYID *keyIDptr = &pkcInfo->keyID;
  858.     CRYPT_ALGO pkcAlgo = pkcInfo->algorithm;
  859.     TIME validFrom, validTo;
  860.     MESSAGE_DIGEST keyID;
  861.     int size;
  862.  
  863.     /* Get the size of the key components */
  864.     if( cryptStatusError( size = sizeofKeyComponents( pkcInfo ) ) )
  865.         return( size );
  866.  
  867.     /* Initialise the ASN.1 types */
  868.     newTime( &validFrom, pkcInfo->validFrom, 0 );
  869.     newTime( &validTo, pkcInfo->validTo, 0 );
  870.     newMessageDigest( &keyID, keyIDptr->hashAlgo, keyIDptr->keyID,
  871.                       keyIDptr->keyIDlength );
  872.  
  873.     /* Write the identifier and length fields */
  874.     if( tag == DEFAULT_TAG )
  875.         writeTag( stream, BER_SEQUENCE );
  876.     else
  877.         writeCtag( stream, tag, TRUE );
  878.     writeLength( stream, size );
  879.  
  880.     /* Write the key ID, validity period, and algorithm ID fields */
  881.     writeMessageDigest( stream, &keyID, DEFAULT_TAG );
  882.     if( pkcInfo->validFrom )
  883.         writeTime( stream, &validFrom, CTAG_PK_VALIDFROM );
  884.     if( pkcInfo->validTo )
  885.         writeTime( stream, &validTo, CTAG_PK_VALIDTO );
  886.     writeEnumerated( stream, pkcAlgo, DEFAULT_TAG );
  887.  
  888.     /* Clean up */
  889.     deleteTime( &validFrom );
  890.     deleteTime( &validTo );
  891.     deleteMessageDigest( &keyID );
  892.  
  893.     /* Since this is an internal routine there's no need for an error check
  894.        at this point */
  895.     return( CRYPT_OK );
  896.     }
  897.  
  898. /* Read a key info/cert header */
  899.  
  900. int _readKeyInfoHeader( STREAM *stream, int *length, const BOOLEAN readIdent )
  901.     {
  902.     int readDataLength = 0;
  903.     long longLength;
  904.  
  905.     /* Read the identifier field if necessary */
  906.     if( readIdent )
  907.         {
  908.         if( readTag( stream ) != BER_SET )
  909.             {
  910.             sSetError( stream, STREAM_BADDATA );
  911.             return( CRYPT_BADDATA );
  912.             }
  913.         readDataLength++;
  914.         }
  915.     readDataLength += readLength( stream, &longLength );
  916.     *length = ( int ) longLength;
  917.     if( checkReadTag( stream, BER_NULL ) )
  918.         {
  919.         readDataLength += readNull( stream );
  920.         *length = 0;
  921.         }
  922.  
  923.     if( sGetStatus( stream ) != STREAM_OK )
  924.         return( sGetStatus( stream ) );
  925.     return( readDataLength );
  926.     }
  927.  
  928. /* Write a key info/cert header */
  929.  
  930. int writeKeyInfoHeader( STREAM *stream, int length, const int tag )
  931.     {
  932.     /* Write the identifier and length fields */
  933.     if( tag == DEFAULT_TAG )
  934.         writeTag( stream, BER_SET );
  935.     else
  936.         writeCtag( stream, tag, TRUE );
  937.     if( !length )
  938.         {
  939.         writeLength( stream, sizeofNull() );
  940.         writeNull( stream, DEFAULT_TAG );
  941.         }
  942.     else
  943.         writeLength( stream, ( int ) sizeofObject( RESTART_MARKER_SIZE ) + length );
  944.  
  945.     return( sGetStatus( stream ) );
  946.     }
  947.  
  948. /* Read a public or private key value */
  949.  
  950. int _readKey( STREAM *stream, PKC_INFO *pkcInfo, const BOOLEAN readIdent,
  951.               const BOOLEAN isPublicKey )
  952.     {
  953.     int readDataLength, length;
  954.  
  955.     /* Read the header field */
  956.     readDataLength = readKeyHeader( stream, pkcInfo, &length, readIdent );
  957.     if( cryptStatusError( readDataLength ) )
  958.         return( readDataLength );
  959.  
  960.     /* Read the PKC information */
  961.     switch( pkcInfo->algorithm )
  962.         {
  963.         case CRYPT_ALGO_DH:
  964.             readDataLength += readDHcomponents( stream,
  965.                         ( CRYPT_PKCINFO_DH * ) pkcInfo->keyInfo );
  966.             break;
  967.  
  968.         case CRYPT_ALGO_RSA:
  969.             readDataLength += readRSAcomponents( stream,
  970.                         ( CRYPT_PKCINFO_RSA * ) pkcInfo->keyInfo, isPublicKey );
  971.             break;
  972.  
  973.         case CRYPT_ALGO_DSA:
  974.             readDataLength += readDSAcomponents( stream,
  975.                         ( CRYPT_PKCINFO_DSA * ) pkcInfo->keyInfo, isPublicKey );
  976.             break;
  977.  
  978.         default:
  979.             sSkip( stream, length );
  980.             return( CRYPT_NOALGO );
  981.         }
  982.  
  983.     if( sGetStatus( stream ) != STREAM_OK )
  984.         return( sGetStatus( stream ) );
  985.     return( readDataLength );
  986.     }
  987.  
  988. /* Write a public or private key */
  989.  
  990. int writeKey( STREAM *stream, PKC_INFO *pkcInfo, const int tag )
  991.     {
  992.     /* Write the general record header */
  993.     writeKeyHeader( stream, tag, pkcInfo );
  994.  
  995.     /* Write the PKC information */
  996.     switch( pkcInfo->algorithm )
  997.         {
  998.         case CRYPT_ALGO_DH:
  999.             writeDHcomponents( stream,
  1000.                     ( CRYPT_PKCINFO_DH * ) pkcInfo->keyInfo );
  1001.             break;
  1002.  
  1003.         case CRYPT_ALGO_RSA:
  1004.             writeRSAcomponents( stream,
  1005.                     ( CRYPT_PKCINFO_RSA * ) pkcInfo->keyInfo );
  1006.             break;
  1007.  
  1008.         case CRYPT_ALGO_DSA:
  1009.             writeDSAcomponents( stream,
  1010.                     ( CRYPT_PKCINFO_DSA * ) pkcInfo->keyInfo );
  1011.             break;
  1012.  
  1013.         default:
  1014.             return( CRYPT_ERROR );    /* Internal error, should never happen */
  1015.         }
  1016.  
  1017.     return( sGetStatus( stream ) );
  1018.     }
  1019. #endif /* FULL_KEYMGMT */
  1020.