1use warnings;
2use strict;
3use Test::More tests => 73;
4use Test::Exception;
5
6use Crypt::MatrixSSL3 qw(:all);
7
8my $certFile            = 't/cert/testserver.crt';
9my $privFile            = 't/cert/testserver.key';
10my $privPass            = undef;
11my $trustedCAcertFiles  = 't/cert/testca.crt';
12
13my ($Server_Keys, $Client_Keys);
14my ($Server_SSL, $Client_SSL);
15
16
17########
18# Init #
19########
20
21lives_ok { $Server_Keys = Crypt::MatrixSSL3::Keys->new() }
22    'Keys->new (server)';
23is PS_SUCCESS, $Server_Keys->load_rsa($certFile, $privFile, $privPass, undef),
24    '$Server_Keys->load_rsa';
25lives_ok { $Server_SSL = Crypt::MatrixSSL3::Server->new($Server_Keys, undef) }
26    'Server->new';
27
28lives_ok { $Client_Keys = Crypt::MatrixSSL3::Keys->new() }
29    'Keys->new (client)';
30is PS_SUCCESS, $Client_Keys->load_rsa(undef, undef, undef, $trustedCAcertFiles),
31    '$Client_Keys->load_rsa';
32lives_ok { $Client_SSL = Crypt::MatrixSSL3::Client->new($Client_Keys, undef, 0, undef, undef, undef) }
33    'Client->new';
34
35#############
36# Handshake #
37#############
38
39my ($client2server, $server2client) = (q{}, q{});
40my ($client_rc, $server_rc);
41while (1) {
42    $server_rc = _decode($Server_SSL, $client2server, $server2client);
43    $client_rc = _decode($Client_SSL, $server2client, $client2server);
44    last if $client_rc || $server_rc;
45}
46is 1, $server_rc, 'handshake complete (server)';
47is 1, $client_rc, 'handshake complete (client)';
48ok !length $client2server, 'client outbuf empty after handshake';
49ok !length $server2client, 'server outbuf empty after handshake';
50
51#######
52# I/O #
53#######
54
55# Simple string, twice
56
57my $s   = "Hello MatrixSSL!\0\n";
58my $tmp = $s;
59my $buf;
60
61ok $Client_SSL->encode_to_outdata($s) > 0,
62    '$Client_SSL->encode_to_outdata';
63is $tmp, $s,
64    q{encode_to_outdata doesn't destroy input string};
65is undef, _decode($Client_SSL, $server2client, $client2server);
66ok length $client2server,
67    'got some outbuf (client)';
68$tmp = $client2server;
69ok $Client_SSL->encode_to_outdata($s) > 0,
70    '$Client_SSL->encode_to_outdata';
71is undef, _decode($Client_SSL, $server2client, $client2server);
72ok length $tmp < length $client2server,
73    'outbuf grow (client)';
74
75is undef, _decode($Server_SSL, $client2server, $server2client, $buf);
76is $buf, $s.$s,
77    'decoded ok (server)';
78ok !length $client2server,
79    'outbuf empty (client)';
80ok !length $server2client,
81    'outbuf empty (server)';
82
83# SSL_MAX_PLAINTEXT_LEN
84
85$s = 'abc' x 123456;
86$tmp = $s;
87$buf = q{};
88while (length $tmp) {
89    ok $Client_SSL->encode_to_outdata(substr($tmp, 0, SSL_MAX_PLAINTEXT_LEN, q{})) > 0,
90        'encode_to_outdata up to SSL_MAX_PLAINTEXT_LEN (client)';
91}
92    is undef, _decode($Client_SSL, $server2client, $client2server),
93        'encoding';
94while (length $client2server) {
95    is undef, _decode($Server_SSL, $client2server, $server2client, $buf),
96        'decoding';
97}
98ok $buf eq $s,
99    'string split into SSL_MAX_PLAINTEXT_LEN chains decoded ok';
100ok !length $client2server,
101    'outbuf empty (client)';
102ok !length $server2client,
103    'outbuf empty (server)';
104
105# More than SSL_MAX_PLAINTEXT_LEN
106
107$s = 'x' x (SSL_MAX_PLAINTEXT_LEN+1);
108is PS_LIMIT_FAIL, $Client_SSL->encode_to_outdata($s),
109    'encode_to_outdata SSL_MAX_PLAINTEXT_LEN+1 failed';
110
111#######
112# Fin #
113#######
114
115undef $Server_SSL;
116undef $Client_SSL;
117undef $Server_Keys;
118undef $Client_Keys;
119ok 1, 'matrixSslClose';
120
121
122###########
123# Helpers #
124###########
125
126sub _decode {
127    my ($ssl) = @_; # other 3 params must be modified in place
128    while (my $n = $ssl->get_readbuf($_[1])) {
129        die error($n) if $n < 0;
130        my $rc = $ssl->received_data($n, my $buf);
131RC:
132        if    ($rc == MATRIXSSL_REQUEST_SEND)       { last          }
133        elsif ($rc == MATRIXSSL_REQUEST_RECV)       { next          }
134        elsif ($rc == MATRIXSSL_HANDSHAKE_COMPLETE) { return 1      }
135        elsif ($rc == MATRIXSSL_RECEIVED_ALERT)     { alert($buf); return -1 }
136        elsif ($rc == MATRIXSSL_APP_DATA)           { $_[3].=$buf   }
137        elsif ($rc == MATRIXSSL_SUCCESS)            { last          }
138        else                                        { die error($rc)}
139        $rc = $ssl->processed_data($buf);
140        goto RC;
141    }
142    while (my $n = $ssl->get_outdata($_[2])) {
143        die error($n) if $n < 0;
144        my $rc = $ssl->sent_data($n);
145        if    ($rc == MATRIXSSL_REQUEST_SEND)       { next          }
146        elsif ($rc == MATRIXSSL_SUCCESS)            { last          }
147        elsif ($rc == MATRIXSSL_REQUEST_CLOSE)      { return -1     }
148        elsif ($rc == MATRIXSSL_HANDSHAKE_COMPLETE) { return 1      }
149        else                                        { die error($rc)}
150    }
151    return;
152}
153
154sub error {
155    my $rc = get_ssl_error($_[0]);
156    return sprintf "MatrixSSL error %d: %s\n", $rc, $rc;
157}
158sub alert {
159    my ($level, $descr) = get_ssl_alert($_[0]);
160    diag sprintf "MatrixSSL alert: level %d: %s, desc %d: %s\n", $level, $level, $descr, $descr;
161    return;
162}
163
164