Beispiel #1
0
static int send_handshake_message( int connection,
                                   int msg_type,
                                   const unsigned char *message,
                                   int message_len,
                                   TLSParameters *parameters )
{
  Handshake     record;
  short         send_buffer_size;
  unsigned char *send_buffer;
  int           response;

  record.msg_type = msg_type;
  record.length = htons( message_len ) << 8; // To deal with 24-bits...
  send_buffer_size = message_len + 4; // space for the handshake header

  send_buffer = ( unsigned char * ) malloc( send_buffer_size );
  send_buffer[ 0 ] = record.msg_type;
  memcpy( send_buffer + 1, &record.length, 3 );
  memcpy( send_buffer + 4, message, message_len );

  update_digest( &parameters->md5_handshake_digest, send_buffer, 
    send_buffer_size );
  update_digest( &parameters->sha1_handshake_digest, send_buffer, 
    send_buffer_size );

  response = send_message( connection, content_handshake, 
                       send_buffer, send_buffer_size, &parameters->active_send_parameters );

  free( send_buffer );

  return response;
}
Beispiel #2
0
static void update_digest_line(HASH_TYPE hash, bool pass, digest_line_t *dline, uint32_t crc, int c)
{
    if (!c) dline->count[0]++;
    dline->chksum[c][0] = update_digest(hash, dline->chksum[c][0], crc);
    if (pass) {
        if (!c) dline->count[1]++;
        dline->chksum[c][1] = update_digest(hash, dline->chksum[c][1], crc);
    }
}
Beispiel #3
0
/* Calculates the digest of a file, if needed.
 */
static int get_file_digest(File* file)
{
    FILE* stream;
    size_t size;
    char buffer[BUFFER_SIZE];

    if (file->status == HASHED)
        return 0;

    init_digest();

    if (file->status == SAMPLED && file->size <= SAMPLE_SIZE)
        update_digest(file->sample, file->size);
    else if (file->size > 0)
    {
        stream = fopen(file->path, "rb");
        if (!stream)
        {
            if (!quiet_flag)
                warning("%s: %s", file->path, strerror(errno));

            file->status = INVALID;
            return -1;
        }

        for (;;)
        {
            size = fread(buffer, 1, sizeof(buffer), stream);
            if (ferror(stream))
            {
                if (!quiet_flag)
                    warning("%s: %s", file->path, strerror(errno));

                fclose(stream);

                file->status = INVALID;
                return -1;
            }

            if (size == 0)
                break;

            update_digest(buffer, size);
        }

        fclose(stream);
    }

    file->digest = malloc(get_digest_size());
    finish_digest(file->digest);
    file->status = HASHED;
    return 0;
}
Beispiel #4
0
int parse_pkcs8_private_key( rsa_key *privkey, 
                             const unsigned char *buffer,
                             int buffer_length,
                             const unsigned char *passphrase )
{   
  struct asn1struct pkcs8_key;
  struct asn1struct private_key;
  struct asn1struct *encryptionId;
  struct asn1struct *salt;
  struct asn1struct *iteration_count;
  struct asn1struct *encrypted_key;
  struct asn1struct *key_type_oid;
  struct asn1struct *priv_key_data;
  digest_ctx initial_hash;
  int counter;
  unsigned char passphrase_hash_in[ MD5_RESULT_SIZE * sizeof( int ) ];
  unsigned char passphrase_hash_out[ MD5_RESULT_SIZE * sizeof( int ) ];
  unsigned char *decrypted_key;
 
  asn1parse( buffer, buffer_length, &pkcs8_key );
  
  encryptionId = pkcs8_key.children->children;
  if ( memcmp( OID_pbeWithMD5andDES_CBC, encryptionId->data,
               encryptionId->length ) )
  {
    fprintf( stderr, "Unsupported key encryption algorithm\n" );
    asn1free( &pkcs8_key );
    return 1;
  }
  // TODO support more algorithms
  salt = encryptionId->next->children;
  iteration_count = salt->next;
  encrypted_key = pkcs8_key.children->next;

  // ugly typecasting
  counter = ntohs( *iteration_count->data );

  new_md5_digest( &initial_hash );
  update_digest( &initial_hash, passphrase, strlen( passphrase ) );
  update_digest( &initial_hash, salt->data, salt->length );
  finalize_digest( &initial_hash );
  memcpy( passphrase_hash_out, initial_hash.hash,
    initial_hash.hash_len * sizeof( int ) );
  while ( --counter ) 
  {
    memcpy( passphrase_hash_in, passphrase_hash_out,
      sizeof( int ) * MD5_RESULT_SIZE );
    md5_hash( passphrase_hash_in, 
      sizeof( int ) * MD5_RESULT_SIZE,
      ( unsigned int * ) passphrase_hash_out );
  }
  decrypted_key = ( unsigned char * ) malloc( encrypted_key->length );
  des_decrypt( encrypted_key->data, encrypted_key->length, decrypted_key,
    ( unsigned char * ) passphrase_hash_out + DES_KEY_SIZE, 
    ( unsigned char * ) passphrase_hash_out );
    
  // sanity check
  if ( decrypted_key[ encrypted_key->length - 1 ] > 8 )
  {
    fprintf( stderr, "Decryption error, bad padding\n");
    asn1free( &pkcs8_key );
    free( decrypted_key );
    return 1;
  }
  asn1parse( decrypted_key,
    encrypted_key->length - decrypted_key[ encrypted_key->length - 1 ],
    &private_key );
  free( decrypted_key );
  key_type_oid = private_key.children->next->children;
  if ( memcmp( OID_RSAPrivateKey, key_type_oid->data, key_type_oid->length ) )
  {
    fprintf( stderr, "Unsupported private key type" );
    asn1free( &pkcs8_key );
    asn1free( &private_key );
  } 
  
  priv_key_data = private_key.children->next->next;
  
  parse_pkcs8_private_key( privkey, priv_key_data->data, priv_key_data->length, "password" );
  
  asn1free( &pkcs8_key );
  asn1free( &private_key );

  return 0;
}
Beispiel #5
0
/**
 * Read a TLS packet off of the connection (assuming there's one waiting) and try
 * to update the security parameters based on the type of message received.  If
 * the read times out, or if an alert is received, return an error code; return 0
 * on success.
 * TODO - assert that the message received is of the type expected (for example,
 * if a server hello is expected but not received, this is a fatal error per 
 * section 7.3).  returns -1 if an error occurred (this routine will have sent an
 * appropriate alert). Otherwise, return the number of bytes read if the packet 
 * includes application data; 0 if the packet was a handshake.  -1 also indicates 
 * that an alert was received.
 */
static int receive_tls_msg( int connection,
                            char *buffer,
                            int bufsz,	
                            TLSParameters *parameters )
{
  TLSPlaintext  message;
  unsigned char *read_pos, *msg_buf, *decrypted_message, *encrypted_message;
  unsigned char header[ 5 ];  // size of TLSPlaintext
  int bytes_read, accum_bytes;
  int decrypted_length;

  // STEP 1 - read off the TLS Record layer
  // First, check to see if there's any data left over from a previous read.
  // If there is, pass that back up.
  // This means that if the caller isn't quick about reading available data,
  // TLS alerts can be missed.
  if ( parameters->unread_buffer != NULL )
  {
    decrypted_message = parameters->unread_buffer;
    decrypted_length = parameters->unread_length;
    parameters->unread_buffer = NULL;
    parameters->unread_length = 0;

    message.type = content_application_data;
  }
  else
  {
    if ( recv( connection, header, 5, 0 ) <= 0 )
    {
      // No data available; it's up to the caller whether this is an error or not.
      return -1;
    }
    
    message.type = header[ 0 ];
    message.version.major = header[ 1 ];
    message.version.minor = header[ 2 ];
    memcpy( &message.length, header + 3, 2 );
    message.length = htons( message.length );
    encrypted_message = ( char * ) malloc( message.length );

    // keep looping & appending until all bytes are accounted for
    accum_bytes = 0;
    msg_buf = encrypted_message;
    while ( accum_bytes < message.length )
    {
      if ( ( bytes_read = recv( connection, ( void * ) msg_buf, 
             message.length - accum_bytes, 0 ) ) <= 0 )
      {
        int status;
        perror( "While reading a TLS packet" );

        if ( ( status = send_alert_message( connection, 
               illegal_parameter, &parameters->active_send_parameters ) ) )
        {
          free( msg_buf );
          return status;
        }
        return -1;
      }
      accum_bytes += bytes_read;
      msg_buf += bytes_read;
    }
    // If a cipherspec is active, all of "encrypted_message" will be encrypted.  
    // Must decrypt it before continuing.  This will change the message length 
    // in all cases, since decrypting also involves verifying a MAC (unless the 
    // active cipher spec is NULL_WITH_NULL_NULL).
    decrypted_message = NULL;
    decrypted_length = tls_decrypt( header, encrypted_message, message.length,
      &decrypted_message, &parameters->active_recv_parameters );

    free( encrypted_message );

    if ( decrypted_length < 0 )
    {
      send_alert_message( connection, bad_record_mac, 
        &parameters->active_send_parameters );
      return -1;
    }
    parameters->active_recv_parameters.seq_num++;
  }

  read_pos = decrypted_message;
 
  if ( message.type == content_handshake )
  {
    while ( ( read_pos - decrypted_message ) < decrypted_length )
    {
      Handshake handshake;
      const unsigned char *handshake_msg_start = read_pos;

      // Now, read the handshake type and length of the next packet
      // TODO - this fails if the read, above, only got part of the message
      read_pos = read_buffer( ( void * ) &handshake.msg_type, 
               ( void * ) read_pos, 1 );
      handshake.length = read_pos[ 0 ] << 16 | read_pos[ 1 ] << 8 | read_pos[ 2 ];

      read_pos += 3;

      // TODO check for negative or unreasonably long length
      // Now, depending on the type, read in and process the packet itself.
      switch ( handshake.msg_type )
      {
        // Client-side messages
        case server_hello:
          read_pos = parse_server_hello( read_pos, handshake.length, 
             parameters );
          if ( read_pos == NULL )  /* error occurred */
          {
            free( msg_buf );
            send_alert_message( connection, illegal_parameter, &parameters->active_send_parameters );
            return -1;
          }
          break;
        case certificate:
          read_pos = parse_x509_chain( read_pos, handshake.length,
            &parameters->server_public_key );
          if ( read_pos == NULL )
          {
            printf( "Rejected, bad certificate\n" );
            send_alert_message( connection, bad_certificate, &parameters->active_send_parameters );
            return -1;
          }
          break;
        case server_hello_done:
          parameters->server_hello_done = 1;
          break;
        case finished:
          {
            read_pos = parse_finished( read_pos, handshake.length, parameters );
            if ( read_pos == NULL )
            {
              send_alert_message( connection, illegal_parameter, &parameters->active_send_parameters );
              return -1;
            }
          }
          break;
        default:
          printf( "Ignoring unrecognized handshake message %d\n", 
             handshake.msg_type );
          // Silently ignore any unrecognized types per section 6
          // TODO However, out-of-order messages should result in a fatal alert
          // per section 7.4
          read_pos += handshake.length;
          break;
      }

      update_digest( &parameters->md5_handshake_digest, handshake_msg_start, 
        handshake.length + 4 );
      update_digest( &parameters->sha1_handshake_digest, handshake_msg_start, 
        handshake.length + 4 );
    }
  }
  else if ( message.type == content_alert )
  {
    while ( ( read_pos - decrypted_message ) < decrypted_length )
    {
      Alert alert;

      read_pos = read_buffer( ( void * ) &alert.level, 
         ( void * ) read_pos, 1 );
      read_pos = read_buffer( ( void * ) &alert.description, 
         ( void * ) read_pos, 1 );

      report_alert( &alert );

      if ( alert.level == fatal )
      {
        return -1;
      }
    }
  }
  else if ( message.type == content_change_cipher_spec )
  { 
    while ( ( read_pos - decrypted_message ) < decrypted_length )
    {
      unsigned char change_cipher_spec_type;
    
      read_pos = read_buffer( ( void * ) &change_cipher_spec_type, 
        ( void * ) read_pos, 1 );

      if ( change_cipher_spec_type != 1 )
      {
        printf( "Error - received message ChangeCipherSpec, but type != 1\n" );
        exit( 0 );
      }
      else
      {
        parameters->pending_recv_parameters.seq_num = 0;
        memcpy( &parameters->active_recv_parameters,
                &parameters->pending_recv_parameters,
                sizeof( ProtectionParameters ) );
        init_protection_parameters( &parameters->pending_recv_parameters );
      }
    }
  }
  else if ( message.type == content_application_data )
  {
    if ( decrypted_length <= bufsz )
    {
      memcpy( buffer, decrypted_message, decrypted_length );
    }
    else
    {
      // Need to hang on to a buffer of data here and pass it back for the
      // next call
      memcpy( buffer, decrypted_message, bufsz );
      parameters->unread_length = decrypted_length - bufsz;
      parameters->unread_buffer = malloc( parameters->unread_length );
      memcpy( parameters->unread_buffer, decrypted_message + bufsz, 
        parameters->unread_length );

      decrypted_length = bufsz;
    }
  }
  else
  {
    // Ignore content types not understood, per section 6 of the RFC.
    printf( "Ignoring non-recognized content type %d\n", message.type );
  }

  free( decrypted_message );
    
  return decrypted_length;
}