The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.
#!/usr/bin/perl

=head1 NAME

mxgg.pl - Sample MatrixSSL client which grabs the google.com https home page

=head1 SYNOPSIS

	perl mxpp.pl [www.sslhost.com[:443]]

=head1 DESCRIPTION

  "Opens" MatrixSSL
  Opens a socket to your favorite SSL host (or www.google.com:443 if you don't specify one)
  Establishes SSL session
  Issues an HTTP "GET /"
  Reads response
  exits.

=head1 BUGS

  doesn't check certificate validity
  lots of stuff is hard-coded.
  ignores return codes mostly.

=cut


use Crypt::MatrixSSL;
use IO::Socket;

$rc=Crypt::MatrixSSL::matrixSslOpen(); if($rc){die "open fail";} # Let MatrixSSL initialize

# Expects the key files to be in the current directory.  Get the key files from
# either the MatrixSSL.com download, or our Crypt-MatrixSSL package (eg: from CPAN)
# (They *should* have been in the same place you got this sample code from)
$rc=Crypt::MatrixSSL::matrixSslReadKeys( $cmxkeys,
				     'certCln.pem', 
				     'privkeyCln.pem',undef,
				     'CAcertSrv.pem'); if($rc){die "readkeys fail";}

Crypt::MatrixSSL::matrixSslNewSession($cssl, $cmxkeys, 0,0); if($rc){die "newsession fail";}

# This is the bit that would let us run custom cert validation if we needed
# We don't: MatrixSSL already can validate for us (if you've got the right cert files installed)
# Crypt::MatrixSSL::matrixSslSetCertValidator($cssl,0,0);

$host=$ARGV[0];
$host="www.google.com:443" unless($host);
$host.=":443" unless($host=~/:/);
$remote=new IO::Socket::INET(PeerAddr=>$host,Proto=>'tcp') || die "sock:$!"; # Connect to a server

$rc=Crypt::MatrixSSL::matrixSslEncodeClientHello($cssl,$cout,0);if($rc){die "hello fail";} # in SSL, Clients talk 1st




# SSL connections require some back-and-forth chatskis - this loop feeds MatrixSSL with the data until it says we're connected OK.
my($decodeRc)=Crypt::MatrixSSL::mxSSL_PARTIAL;
while(($hc=Crypt::MatrixSSL::matrixSslHandshakeIsComplete($cssl))!=1) {
  print "hc=$hc\n";
  if(length($cout)) {
    $b=syswrite($remote,$cout); die "Socket error: $!" unless(defined($b));
    $cout=substr($cout,$b); print "wrote bytes=$b, new cout_len=" . length($cout) . "\n";
  }
  if(($decodeRc==Crypt::MatrixSSL::mxSSL_PARTIAL)||($decodeRc==Crypt::MatrixSSL::mxSSL_SEND_RESPONSE)) { # -3
    $buf='';$b=sysread($remote,$buf,17000);$cin.=$buf;
    print "Read bytes=$b new cin_len=" .length($cin) . " got: '${\showme($buf)}'\n"; $buf='';
  }

  $decodeRc=-100;
  while( ($decodeRc==-100) || (($decodeRc==0)&&(length($cin)>0))) {
    $decodeRc=Crypt::MatrixSSL::matrixSslDecode($cssl, $cin, $buf, $error, $alertLevel, $alertDescription);
    print "matrixSslDecode rc=$decodeRc($Crypt::MatrixSSL::mxSSL_RETURN_CODES{$decodeRc}) cin_len=" . length($cin) . " cout_len=" . length($cout);
    $cout.=$buf; $buf='';
    # Need to end if $rc hit an error
    if($decodeRc){ print " err=$error ($Crypt::MatrixSSL::mxSSL_ALERT_CODES{$error})"}; print "\n";
    die "oops" if($l++>20);
  }
  die "oops" if($l++>20);
}



# Our client is now going to send a message to the server
$rc=Crypt::MatrixSSL::matrixSslEncode($cssl, "GET / HTTP/1.1\r\nAccept: */*\r\nUser-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)\r\nHost: $host\r\n\r\n", $cout);
syswrite($remote,$cout); print "wrote bytes=" . length($cout) . "\n" if(length($cout));


# Wait for google to talk back to us:-
$b=sysread($remote,$cin,17000); print "Read bytes=$b '${\showme($cin)}'\n";

# Decrypt what it said:-
$rc=Crypt::MatrixSSL::matrixSslDecode($cssl, $cin, $cout, $error, $alertLevel, $alertDescription);
print "Read($rc): '$cout'\n";


# Tell google we're about to go away now
$rc=Crypt::MatrixSSL::matrixSslEncodeClosureAlert($cssl, $cout);
syswrite($remote,$cout); print "wrote bytes=" . length($cout) . "\n" if(length($cout));


# Clear up the finished session now
$rc=Crypt::MatrixSSL::matrixSslDeleteSession($cssl);

# Free our keys
$rc=Crypt::MatrixSSL::matrixSslFreeKeys($cmxkeys);

# Tidy up
Crypt::MatrixSSL::matrixSslClose();

# End!
exit(0);

# Display (possibly binary) data on-screen
sub showme {
  no warnings;
  my($buf,$col2,$src)=@_;
  my $col=$col2; my($red)=''; my($norm)='';

  $buf =~ s/[\000-\011\013-\014\016-\037\177-\377]/"\\$red".unpack("H*",$&)."$col"/esmg; # Do every non-ascii char too
  $buf=~s/\r/$red\\r$col/g;
  #$buf=~s/\n/$red\\n$col\n/g;
  $buf=~s/\n/$red\\n$col/g;
  # &printa("$col$buf$norm\n")  unless($switch{'quiet'});
  return "$col$buf$norm";

}