1*e0c4386eSCy Schubert#! /usr/bin/env perl 2*e0c4386eSCy Schubert# Copyright 2018-2021 The OpenSSL Project Authors. All Rights Reserved. 3*e0c4386eSCy Schubert# 4*e0c4386eSCy Schubert# Licensed under the Apache License 2.0 (the "License"). You may not use 5*e0c4386eSCy Schubert# this file except in compliance with the License. You can obtain a copy 6*e0c4386eSCy Schubert# in the file LICENSE in the source distribution or at 7*e0c4386eSCy Schubert# https://www.openssl.org/source/license.html 8*e0c4386eSCy Schubert 9*e0c4386eSCy Schubert 10*e0c4386eSCy Schubertuse strict; 11*e0c4386eSCy Schubertuse warnings; 12*e0c4386eSCy Schubert 13*e0c4386eSCy Schubertuse OpenSSL::Test; 14*e0c4386eSCy Schubertuse OpenSSL::Test::Utils; 15*e0c4386eSCy Schubertuse Storable qw(dclone); 16*e0c4386eSCy Schubert 17*e0c4386eSCy Schubertsetup("test_mac"); 18*e0c4386eSCy Schubert 19*e0c4386eSCy Schubertmy @mac_tests = ( 20*e0c4386eSCy Schubert { cmd => [qw{openssl mac -digest SHA1 -macopt hexkey:000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F}], 21*e0c4386eSCy Schubert type => 'HMAC', 22*e0c4386eSCy Schubert input => unpack("H*", "Sample message for keylen=blocklen"), 23*e0c4386eSCy Schubert expected => '5FD596EE78D5553C8FF4E72D266DFD192366DA29', 24*e0c4386eSCy Schubert desc => 'HMAC SHA1' }, 25*e0c4386eSCy Schubert { cmd => [qw{openssl mac -macopt digest:SHA1 -macopt hexkey:000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F}], 26*e0c4386eSCy Schubert type => 'HMAC', 27*e0c4386eSCy Schubert input => unpack("H*", "Sample message for keylen=blocklen"), 28*e0c4386eSCy Schubert expected => '5FD596EE78D5553C8FF4E72D266DFD192366DA29', 29*e0c4386eSCy Schubert desc => 'HMAC SHA1 via -macopt' }, 30*e0c4386eSCy Schubert { cmd => [qw{openssl mac -cipher AES-256-GCM -macopt hexkey:4C973DBC7364621674F8B5B89E5C15511FCED9216490FB1C1A2CAA0FFE0407E5 -macopt hexiv:7AE8E2CA4EC500012E58495C}], 31*e0c4386eSCy Schubert type => 'GMAC', 32*e0c4386eSCy Schubert input => '68F2E77696CE7AE8E2CA4EC588E541002E58495C08000F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D0007', 33*e0c4386eSCy Schubert expected => '00BDA1B7E87608BCBF470F12157F4C07', 34*e0c4386eSCy Schubert desc => 'GMAC' }, 35*e0c4386eSCy Schubert { cmd => [qw{openssl mac -macopt cipher:AES-256-GCM -macopt hexkey:4C973DBC7364621674F8B5B89E5C15511FCED9216490FB1C1A2CAA0FFE0407E5 -macopt hexiv:7AE8E2CA4EC500012E58495C}], 36*e0c4386eSCy Schubert type => 'GMAC', 37*e0c4386eSCy Schubert input => '68F2E77696CE7AE8E2CA4EC588E541002E58495C08000F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D0007', 38*e0c4386eSCy Schubert expected => '00BDA1B7E87608BCBF470F12157F4C07', 39*e0c4386eSCy Schubert desc => 'GMAC via -macopt' }, 40*e0c4386eSCy Schubert { cmd => [qw{openssl mac -macopt hexkey:404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F -macopt xof:0}], 41*e0c4386eSCy Schubert type => 'KMAC128', 42*e0c4386eSCy Schubert input => '00010203', 43*e0c4386eSCy Schubert expected => 'E5780B0D3EA6F7D3A429C5706AA43A00FADBD7D49628839E3187243F456EE14E', 44*e0c4386eSCy Schubert desc => 'KMAC128' }, 45*e0c4386eSCy Schubert { cmd => [qw{openssl mac -macopt hexkey:404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F -macopt }, 'custom:My Tagged Application'], 46*e0c4386eSCy Schubert type => 'KMAC256', 47*e0c4386eSCy Schubert input => '00010203', 48*e0c4386eSCy Schubert expected => '20C570C31346F703C9AC36C61C03CB64C3970D0CFC787E9B79599D273A68D2F7F69D4CC3DE9D104A351689F27CF6F5951F0103F33F4F24871024D9C27773A8DD', 49*e0c4386eSCy Schubert desc => 'KMAC256' }, 50*e0c4386eSCy Schubert { cmd => [qw{openssl mac -macopt hexkey:404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F -macopt xof:1 -macopt}, 'custom:My Tagged Application'], 51*e0c4386eSCy Schubert type => 'KMAC256', 52*e0c4386eSCy Schubert input => '000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7', 53*e0c4386eSCy Schubert expected => 'D5BE731C954ED7732846BB59DBE3A8E30F83E77A4BFF4459F2F1C2B4ECEBB8CE67BA01C62E8AB8578D2D499BD1BB276768781190020A306A97DE281DCC30305D', 54*e0c4386eSCy Schubert desc => 'KMAC256 with xof len of 64' }, 55*e0c4386eSCy Schubert); 56*e0c4386eSCy Schubert 57*e0c4386eSCy Schubertmy @siphash_tests = ( 58*e0c4386eSCy Schubert { cmd => [qw{openssl mac -macopt hexkey:000102030405060708090A0B0C0D0E0F}], 59*e0c4386eSCy Schubert type => 'SipHash', 60*e0c4386eSCy Schubert input => '00', 61*e0c4386eSCy Schubert expected => 'da87c1d86b99af44347659119b22fc45', 62*e0c4386eSCy Schubert desc => 'SipHash No input' } 63*e0c4386eSCy Schubert); 64*e0c4386eSCy Schubert 65*e0c4386eSCy Schubertmy @cmac_tests = ( 66*e0c4386eSCy Schubert { cmd => [qw{openssl mac -cipher AES-256-CBC -macopt hexkey:0B122AC8F34ED1FE082A3625D157561454167AC145A10BBF77C6A70596D574F1}], 67*e0c4386eSCy Schubert type => 'CMAC', 68*e0c4386eSCy Schubert input => '498B53FDEC87EDCBF07097DCCDE93A084BAD7501A224E388DF349CE18959FE8485F8AD1537F0D896EA73BEDC7214713F', 69*e0c4386eSCy Schubert expected => 'F62C46329B41085625669BAF51DEA66A', 70*e0c4386eSCy Schubert desc => 'CMAC AES-256-CBC' }, 71*e0c4386eSCy Schubert { cmd => [qw{openssl mac -macopt cipher:AES-256-CBC -macopt hexkey:0B122AC8F34ED1FE082A3625D157561454167AC145A10BBF77C6A70596D574F1}], 72*e0c4386eSCy Schubert type => 'CMAC', 73*e0c4386eSCy Schubert input => '498B53FDEC87EDCBF07097DCCDE93A084BAD7501A224E388DF349CE18959FE8485F8AD1537F0D896EA73BEDC7214713F', 74*e0c4386eSCy Schubert expected => 'F62C46329B41085625669BAF51DEA66A', 75*e0c4386eSCy Schubert desc => 'CMAC AES-256-CBC' }, 76*e0c4386eSCy Schubert); 77*e0c4386eSCy Schubert 78*e0c4386eSCy Schubertmy @poly1305_tests = ( 79*e0c4386eSCy Schubert { cmd => [qw{openssl mac -macopt hexkey:02000000000000000000000000000000ffffffffffffffffffffffffffffffff}], 80*e0c4386eSCy Schubert type => 'Poly1305', 81*e0c4386eSCy Schubert input => '02000000000000000000000000000000', 82*e0c4386eSCy Schubert expected => '03000000000000000000000000000000', 83*e0c4386eSCy Schubert desc => 'Poly1305 (wrap 2^128)' }, 84*e0c4386eSCy Schubert); 85*e0c4386eSCy Schubert 86*e0c4386eSCy Schubertpush @mac_tests, @siphash_tests unless disabled("siphash"); 87*e0c4386eSCy Schubertpush @mac_tests, @cmac_tests unless disabled("cmac"); 88*e0c4386eSCy Schubertpush @mac_tests, @poly1305_tests unless disabled("poly1305"); 89*e0c4386eSCy Schubert 90*e0c4386eSCy Schubertmy @mac_fail_tests = ( 91*e0c4386eSCy Schubert { cmd => [qw{openssl mac}], 92*e0c4386eSCy Schubert type => 'KMAC128', 93*e0c4386eSCy Schubert input => '00', 94*e0c4386eSCy Schubert err => 'EVP_MAC_Init', 95*e0c4386eSCy Schubert desc => 'KMAC128 Fail no key' }, 96*e0c4386eSCy Schubert { cmd => [qw{openssl mac -propquery unknown -macopt hexkey:404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F}], 97*e0c4386eSCy Schubert type => 'KMAC128', 98*e0c4386eSCy Schubert input => '00', 99*e0c4386eSCy Schubert err => 'Invalid MAC name KMAC128', 100*e0c4386eSCy Schubert desc => 'KMAC128 Fail unknown property' }, 101*e0c4386eSCy Schubert { cmd => [qw{openssl mac -cipher AES-128-CBC -macopt hexkey:00}], 102*e0c4386eSCy Schubert type => 'HMAC', 103*e0c4386eSCy Schubert input => '00', 104*e0c4386eSCy Schubert err => 'MAC parameter error', 105*e0c4386eSCy Schubert desc => 'HMAC given a cipher' }, 106*e0c4386eSCy Schubert); 107*e0c4386eSCy Schubert 108*e0c4386eSCy Schubertmy @siphash_fail_tests = ( 109*e0c4386eSCy Schubert { cmd => [qw{openssl mac}], 110*e0c4386eSCy Schubert type => 'SipHash', 111*e0c4386eSCy Schubert input => '00', 112*e0c4386eSCy Schubert err => '', 113*e0c4386eSCy Schubert desc => 'SipHash Fail no key' }, 114*e0c4386eSCy Schubert); 115*e0c4386eSCy Schubert 116*e0c4386eSCy Schubertpush @mac_fail_tests, @siphash_fail_tests unless disabled("siphash"); 117*e0c4386eSCy Schubert 118*e0c4386eSCy Schubertplan tests => (scalar @mac_tests * 2) + scalar @mac_fail_tests; 119*e0c4386eSCy Schubert 120*e0c4386eSCy Schubertmy $test_count = 0; 121*e0c4386eSCy Schubert 122*e0c4386eSCy Schubertforeach (@mac_tests) { 123*e0c4386eSCy Schubert $test_count++; 124*e0c4386eSCy Schubert ok(compareline($_->{cmd}, $_->{type}, $_->{input}, $_->{expected}, $_->{err}), $_->{desc}); 125*e0c4386eSCy Schubert} 126*e0c4386eSCy Schubertforeach (@mac_tests) { 127*e0c4386eSCy Schubert $test_count++; 128*e0c4386eSCy Schubert ok(comparefile($_->{cmd}, $_->{type}, $_->{input}, $_->{expected}), $_->{desc}); 129*e0c4386eSCy Schubert} 130*e0c4386eSCy Schubert 131*e0c4386eSCy Schubertforeach (@mac_fail_tests) { 132*e0c4386eSCy Schubert $test_count++; 133*e0c4386eSCy Schubert ok(compareline($_->{cmd}, $_->{type}, $_->{input}, $_->{expected}, $_->{err}), $_->{desc}); 134*e0c4386eSCy Schubert} 135*e0c4386eSCy Schubert 136*e0c4386eSCy Schubert# Create a temp input file and save the input data into it, and 137*e0c4386eSCy Schubert# then compare the stdout output matches the expected value. 138*e0c4386eSCy Schubertsub compareline { 139*e0c4386eSCy Schubert my $tmpfile = "input-$test_count.bin"; 140*e0c4386eSCy Schubert my ($cmdarray_orig, $type, $input, $expect, $err) = @_; 141*e0c4386eSCy Schubert my $cmdarray = dclone $cmdarray_orig; 142*e0c4386eSCy Schubert if (defined($expect)) { 143*e0c4386eSCy Schubert $expect = uc $expect; 144*e0c4386eSCy Schubert } 145*e0c4386eSCy Schubert # Open a temporary input file and write $input to it 146*e0c4386eSCy Schubert open(my $in, '>', $tmpfile) or die "Could not open file"; 147*e0c4386eSCy Schubert binmode($in); 148*e0c4386eSCy Schubert my $bin = pack("H*", $input); 149*e0c4386eSCy Schubert print $in $bin; 150*e0c4386eSCy Schubert close $in; 151*e0c4386eSCy Schubert 152*e0c4386eSCy Schubert # The last cmd parameter is the temporary input file we just created. 153*e0c4386eSCy Schubert my @other = ('-in', $tmpfile, $type); 154*e0c4386eSCy Schubert push @$cmdarray, @other; 155*e0c4386eSCy Schubert 156*e0c4386eSCy Schubert my @lines = run(app($cmdarray), capture => 1); 157*e0c4386eSCy Schubert # Not unlinking $tmpfile 158*e0c4386eSCy Schubert 159*e0c4386eSCy Schubert if (defined($expect)) { 160*e0c4386eSCy Schubert if ($lines[0] =~ m|^\Q${expect}\E\R$|) { 161*e0c4386eSCy Schubert return 1; 162*e0c4386eSCy Schubert } else { 163*e0c4386eSCy Schubert print "Got: $lines[0]"; 164*e0c4386eSCy Schubert print "Exp: $expect\n"; 165*e0c4386eSCy Schubert return 0; 166*e0c4386eSCy Schubert } 167*e0c4386eSCy Schubert } 168*e0c4386eSCy Schubert if (defined($err)) { 169*e0c4386eSCy Schubert if (defined($lines[0])) { 170*e0c4386eSCy Schubert $lines[0] =~ s/\s+$//; 171*e0c4386eSCy Schubert if ($lines[0] eq $err) { 172*e0c4386eSCy Schubert return 1; 173*e0c4386eSCy Schubert } else { 174*e0c4386eSCy Schubert print "Got: $lines[0]"; 175*e0c4386eSCy Schubert print "Exp: $err\n"; 176*e0c4386eSCy Schubert return 0; 177*e0c4386eSCy Schubert } 178*e0c4386eSCy Schubert } else { 179*e0c4386eSCy Schubert # expected an error 180*e0c4386eSCy Schubert return 1; 181*e0c4386eSCy Schubert } 182*e0c4386eSCy Schubert } 183*e0c4386eSCy Schubert return 0; 184*e0c4386eSCy Schubert} 185*e0c4386eSCy Schubert 186*e0c4386eSCy Schubert# Create a temp input file and save the input data into it, and 187*e0c4386eSCy Schubert# use the '-bin -out <file>' commandline options to save results out to a file. 188*e0c4386eSCy Schubert# Read this file back in and check its output matches the expected value. 189*e0c4386eSCy Schubertsub comparefile { 190*e0c4386eSCy Schubert my $tmpfile = "input-$test_count.bin"; 191*e0c4386eSCy Schubert my $outfile = "output-$test_count.bin"; 192*e0c4386eSCy Schubert my ($cmdarray, $type, $input, $expect) = @_; 193*e0c4386eSCy Schubert $expect = uc $expect; 194*e0c4386eSCy Schubert 195*e0c4386eSCy Schubert # Open a temporary input file and write $input to it 196*e0c4386eSCy Schubert open(my $in, '>', $tmpfile) or die "Could not open file"; 197*e0c4386eSCy Schubert binmode($in); 198*e0c4386eSCy Schubert my $bin = pack("H*", $input); 199*e0c4386eSCy Schubert print $in $bin; 200*e0c4386eSCy Schubert close $in; 201*e0c4386eSCy Schubert 202*e0c4386eSCy Schubert my @other = ("-binary", "-in", $tmpfile, "-out", $outfile, $type); 203*e0c4386eSCy Schubert push @$cmdarray, @other; 204*e0c4386eSCy Schubert 205*e0c4386eSCy Schubert run(app($cmdarray)); 206*e0c4386eSCy Schubert # Not unlinking $tmpfile 207*e0c4386eSCy Schubert 208*e0c4386eSCy Schubert open(my $out, '<', $outfile) or die "Could not open file"; 209*e0c4386eSCy Schubert binmode($out); 210*e0c4386eSCy Schubert my $buffer; 211*e0c4386eSCy Schubert my $BUFSIZE = 1024; 212*e0c4386eSCy Schubert read($out, $buffer, $BUFSIZE) or die "unable to read"; 213*e0c4386eSCy Schubert my $line = uc unpack("H*", $buffer); 214*e0c4386eSCy Schubert close($out); 215*e0c4386eSCy Schubert # Not unlinking $outfile 216*e0c4386eSCy Schubert 217*e0c4386eSCy Schubert if ($line eq $expect) { 218*e0c4386eSCy Schubert return 1; 219*e0c4386eSCy Schubert } else { 220*e0c4386eSCy Schubert print "Got: $line\n"; 221*e0c4386eSCy Schubert print "Exp: $expect\n"; 222*e0c4386eSCy Schubert return 0; 223*e0c4386eSCy Schubert } 224*e0c4386eSCy Schubert} 225