03-test_fipsinstall.t 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. #! /usr/bin/env perl
  2. # Copyright 2019-2023 The OpenSSL Project Authors. All Rights Reserved.
  3. #
  4. # Licensed under the Apache License 2.0 (the "License"). You may not use
  5. # this file except in compliance with the License. You can obtain a copy
  6. # in the file LICENSE in the source distribution or at
  7. # https://www.openssl.org/source/license.html
  8. use strict;
  9. use warnings;
  10. use File::Spec::Functions qw(:DEFAULT abs2rel);
  11. use File::Copy;
  12. use OpenSSL::Glob;
  13. use OpenSSL::Test qw/:DEFAULT srctop_dir srctop_file bldtop_dir bldtop_file/;
  14. use OpenSSL::Test::Utils;
  15. BEGIN {
  16. setup("test_fipsinstall");
  17. }
  18. use lib srctop_dir('Configurations');
  19. use lib bldtop_dir('.');
  20. use platform;
  21. plan skip_all => "Test only supported in a fips build" if disabled("fips");
  22. # Compatible options for pedantic FIPS compliance
  23. my @pedantic_okay =
  24. ( 'ems_check', 'no_drbg_truncated_digests', 'self_test_onload' );
  25. # Incompatible options for pedantic FIPS compliance
  26. my @pedantic_fail =
  27. ( 'no_conditional_errors', 'no_security_checks', 'self_test_oninstall' );
  28. plan tests => 35 + (scalar @pedantic_okay) + (scalar @pedantic_fail);
  29. my $infile = bldtop_file('providers', platform->dso('fips'));
  30. my $fipskey = $ENV{FIPSKEY} // config('FIPSKEY') // '00';
  31. my $provconf = srctop_file("test", "fips-and-base.cnf");
  32. # Read in a text $infile and replace the regular expression in $srch with the
  33. # value in $repl and output to a new file $outfile.
  34. sub replace_line_file_internal {
  35. my ($infile, $srch, $repl, $outfile) = @_;
  36. my $msg;
  37. open(my $in, "<", $infile) or return 0;
  38. read($in, $msg, 1024);
  39. close $in;
  40. $msg =~ s/$srch/$repl/;
  41. open(my $fh, ">", $outfile) or return 0;
  42. print $fh $msg;
  43. close $fh;
  44. return 1;
  45. }
  46. # Read in the text input file 'fips.cnf'
  47. # and replace a single Key = Value line with a new value in $value.
  48. # OR remove the Key = Value line if the passed in $value is empty.
  49. # and then output a new file $outfile.
  50. # $key is the Key to find
  51. sub replace_line_file {
  52. my ($key, $value, $outfile) = @_;
  53. my $srch = qr/$key\s*=\s*\S*\n/;
  54. my $rep;
  55. if ($value eq "") {
  56. $rep = "";
  57. } else {
  58. $rep = "$key = $value\n";
  59. }
  60. return replace_line_file_internal('fips.cnf', $srch, $rep, $outfile);
  61. }
  62. # Read in the text input file 'test/fips.cnf'
  63. # and replace the .cnf file used in
  64. # .include fipsmodule.cnf with a new value in $value.
  65. # and then output a new file $outfile.
  66. # $key is the Key to find
  67. sub replace_parent_line_file {
  68. my ($value, $outfile) = @_;
  69. my $srch = qr/fipsmodule.cnf/;
  70. my $rep = "$value";
  71. return replace_line_file_internal(srctop_file("test", 'fips.cnf'),
  72. $srch, $rep, $outfile);
  73. }
  74. # Check if the specified pattern occurs in the given file
  75. # Returns 1 if the pattern is found and 0 if not
  76. sub find_line_file {
  77. my ($key, $file) = @_;
  78. open(my $in, $file) or return -1;
  79. while (my $line = <$in>) {
  80. if ($line =~ /$key/) {
  81. close($in);
  82. return 1;
  83. }
  84. }
  85. close($in);
  86. return 0;
  87. }
  88. # fail if no module name
  89. ok(!run(app(['openssl', 'fipsinstall', '-out', 'fips.cnf', '-module',
  90. '-provider_name', 'fips',
  91. '-macopt', 'digest:SHA256', '-macopt', "hexkey:$fipskey",
  92. '-section_name', 'fips_sect'])),
  93. "fipsinstall fail");
  94. # fail to verify if the configuration file is missing
  95. ok(!run(app(['openssl', 'fipsinstall', '-in', 'dummy.tmp', '-module', $infile,
  96. '-provider_name', 'fips', '-mac_name', 'HMAC',
  97. '-macopt', 'digest:SHA256', '-macopt', "hexkey:$fipskey",
  98. '-section_name', 'fips_sect', '-verify'])),
  99. "fipsinstall verify fail");
  100. # output a fips.cnf file containing mac data
  101. ok(run(app(['openssl', 'fipsinstall', '-out', 'fips.cnf', '-module', $infile,
  102. '-provider_name', 'fips', '-mac_name', 'HMAC',
  103. '-macopt', 'digest:SHA256', '-macopt', "hexkey:$fipskey",
  104. '-section_name', 'fips_sect'])),
  105. "fipsinstall");
  106. # verify the fips.cnf file
  107. ok(run(app(['openssl', 'fipsinstall', '-in', 'fips.cnf', '-module', $infile,
  108. '-provider_name', 'fips', '-mac_name', 'HMAC',
  109. '-macopt', 'digest:SHA256', '-macopt', "hexkey:$fipskey",
  110. '-section_name', 'fips_sect', '-verify'])),
  111. "fipsinstall verify");
  112. ok(replace_line_file('module-mac', '', 'fips_no_module_mac.cnf')
  113. && !run(app(['openssl', 'fipsinstall',
  114. '-in', 'fips_no_module_mac.cnf',
  115. '-module', $infile,
  116. '-provider_name', 'fips', '-mac_name', 'HMAC',
  117. '-macopt', 'digest:SHA256', '-macopt', "hexkey:01",
  118. '-section_name', 'fips_sect', '-verify'])),
  119. "fipsinstall verify fail no module mac");
  120. ok(replace_line_file('install-mac', '', 'fips_no_install_mac.cnf')
  121. && !run(app(['openssl', 'fipsinstall',
  122. '-in', 'fips_no_install_mac.cnf',
  123. '-module', $infile,
  124. '-provider_name', 'fips', '-mac_name', 'HMAC',
  125. '-macopt', 'digest:SHA256', '-macopt', "hexkey:01",
  126. '-section_name', 'fips_sect', '-verify'])),
  127. "fipsinstall verify fail no install indicator mac");
  128. ok(replace_line_file('module-mac', '00:00:00:00:00:00',
  129. 'fips_bad_module_mac.cnf')
  130. && !run(app(['openssl', 'fipsinstall',
  131. '-in', 'fips_bad_module_mac.cnf',
  132. '-module', $infile,
  133. '-provider_name', 'fips', '-mac_name', 'HMAC',
  134. '-macopt', 'digest:SHA256', '-macopt', "hexkey:01",
  135. '-section_name', 'fips_sect', '-verify'])),
  136. "fipsinstall verify fail if invalid module integrity value");
  137. ok(replace_line_file('install-mac', '00:00:00:00:00:00',
  138. 'fips_bad_install_mac.cnf')
  139. && !run(app(['openssl', 'fipsinstall',
  140. '-in', 'fips_bad_install_mac.cnf',
  141. '-module', $infile,
  142. '-provider_name', 'fips', '-mac_name', 'HMAC',
  143. '-macopt', 'digest:SHA256', '-macopt', "hexkey:01",
  144. '-section_name', 'fips_sect', '-verify'])),
  145. "fipsinstall verify fail if invalid install indicator integrity value");
  146. ok(replace_line_file('install-status', 'INCORRECT_STATUS_STRING',
  147. 'fips_bad_indicator.cnf')
  148. && !run(app(['openssl', 'fipsinstall',
  149. '-in', 'fips_bad_indicator.cnf',
  150. '-module', $infile,
  151. '-provider_name', 'fips', '-mac_name', 'HMAC',
  152. '-macopt', 'digest:SHA256', '-macopt', "hexkey:01",
  153. '-section_name', 'fips_sect', '-verify'])),
  154. "fipsinstall verify fail if invalid install indicator status");
  155. # fail to verify the fips.cnf file if a different key is used
  156. ok(!run(app(['openssl', 'fipsinstall', '-in', 'fips.cnf', '-module', $infile,
  157. '-provider_name', 'fips', '-mac_name', 'HMAC',
  158. '-macopt', 'digest:SHA256', '-macopt', "hexkey:01",
  159. '-section_name', 'fips_sect', '-verify'])),
  160. "fipsinstall verify fail bad key");
  161. # fail to verify the fips.cnf file if a different mac digest is used
  162. ok(!run(app(['openssl', 'fipsinstall', '-in', 'fips.cnf', '-module', $infile,
  163. '-provider_name', 'fips', '-mac_name', 'HMAC',
  164. '-macopt', 'digest:SHA512', '-macopt', "hexkey:$fipskey",
  165. '-section_name', 'fips_sect', '-verify'])),
  166. "fipsinstall verify fail incorrect digest");
  167. # corrupt the module hmac
  168. ok(!run(app(['openssl', 'fipsinstall', '-out', 'fips.cnf', '-module', $infile,
  169. '-provider_name', 'fips', '-mac_name', 'HMAC',
  170. '-macopt', 'digest:SHA256', '-macopt', "hexkey:$fipskey",
  171. '-section_name', 'fips_sect', '-corrupt_desc', 'HMAC'])),
  172. "fipsinstall fails when the module integrity is corrupted");
  173. # corrupt the first digest
  174. ok(!run(app(['openssl', 'fipsinstall', '-out', 'fips_fail.cnf', '-module', $infile,
  175. '-provider_name', 'fips', '-mac_name', 'HMAC',
  176. '-macopt', 'digest:SHA256', '-macopt', "hexkey:$fipskey",
  177. '-section_name', 'fips_sect', '-corrupt_desc', 'SHA1'])),
  178. "fipsinstall fails when the digest result is corrupted");
  179. # corrupt another digest
  180. ok(!run(app(['openssl', 'fipsinstall', '-out', 'fips_fail.cnf', '-module', $infile,
  181. '-provider_name', 'fips', '-mac_name', 'HMAC',
  182. '-macopt', 'digest:SHA256', '-macopt', "hexkey:$fipskey",
  183. '-section_name', 'fips_sect', '-corrupt_desc', 'SHA3'])),
  184. "fipsinstall fails when the digest result is corrupted");
  185. # corrupt cipher encrypt test
  186. ok(!run(app(['openssl', 'fipsinstall', '-out', 'fips_fail.cnf', '-module', $infile,
  187. '-provider_name', 'fips', '-mac_name', 'HMAC',
  188. '-macopt', 'digest:SHA256', '-macopt', "hexkey:$fipskey",
  189. '-section_name', 'fips_sect', '-corrupt_desc', 'AES_GCM'])),
  190. "fipsinstall fails when the AES_GCM result is corrupted");
  191. # corrupt cipher decrypt test
  192. ok(!run(app(['openssl', 'fipsinstall', '-out', 'fips_fail.cnf', '-module', $infile,
  193. '-provider_name', 'fips', '-mac_name', 'HMAC',
  194. '-macopt', 'digest:SHA256', '-macopt', "hexkey:$fipskey",
  195. '-section_name', 'fips_sect', '-corrupt_desc', 'AES_ECB_Decrypt'])),
  196. "fipsinstall fails when the AES_ECB result is corrupted");
  197. # corrupt DRBG
  198. ok(!run(app(['openssl', 'fipsinstall', '-out', 'fips_fail.cnf', '-module', $infile,
  199. '-provider_name', 'fips', '-mac_name', 'HMAC',
  200. '-macopt', 'digest:SHA256', '-macopt', "hexkey:$fipskey",
  201. '-section_name', 'fips_sect', '-corrupt_desc', 'CTR'])),
  202. "fipsinstall fails when the DRBG CTR result is corrupted");
  203. # corrupt a KAS test
  204. SKIP: {
  205. skip "Skipping KAS DH corruption test because of no dh in this build", 1
  206. if disabled("dh");
  207. ok(!run(app(['openssl', 'fipsinstall', '-out', 'fips.cnf', '-module', $infile,
  208. '-provider_name', 'fips', '-mac_name', 'HMAC',
  209. '-macopt', 'digest:SHA256', '-macopt', "hexkey:$fipskey",
  210. '-section_name', 'fips_sect',
  211. '-corrupt_desc', 'DH',
  212. '-corrupt_type', 'KAT_KA'])),
  213. "fipsinstall fails when the kas result is corrupted");
  214. }
  215. # corrupt a Signature test - 140-3 requires a known answer test
  216. SKIP: {
  217. skip "Skipping Signature DSA corruption test because of no dsa in this build", 1
  218. if disabled("dsa");
  219. run(test(["fips_version_test", "-config", $provconf, ">=3.1.0"]),
  220. capture => 1, statusvar => \my $exit);
  221. skip "FIPS provider version is too old for KAT DSA signature test", 1
  222. if !$exit;
  223. ok(!run(app(['openssl', 'fipsinstall', '-out', 'fips.cnf', '-module', $infile,
  224. '-provider_name', 'fips', '-mac_name', 'HMAC',
  225. '-macopt', 'digest:SHA256', '-macopt', "hexkey:$fipskey",
  226. '-section_name', 'fips_sect', '-self_test_oninstall',
  227. '-corrupt_desc', 'DSA',
  228. '-corrupt_type', 'KAT_Signature'])),
  229. "fipsinstall fails when the signature result is corrupted");
  230. }
  231. # corrupt a Signature test - 140-2 allows a pairwise consistency test
  232. SKIP: {
  233. skip "Skipping Signature DSA corruption test because of no dsa in this build", 1
  234. if disabled("dsa");
  235. run(test(["fips_version_test", "-config", $provconf, "<3.1.0"]),
  236. capture => 1, statusvar => \my $exit);
  237. skip "FIPS provider version is too new for PCT DSA signature test", 1
  238. if !$exit;
  239. ok(!run(app(['openssl', 'fipsinstall', '-out', 'fips.cnf', '-module', $infile,
  240. '-provider_name', 'fips', '-mac_name', 'HMAC',
  241. '-macopt', 'digest:SHA256', '-macopt', "hexkey:$fipskey",
  242. '-section_name', 'fips_sect',
  243. '-corrupt_desc', 'DSA',
  244. '-corrupt_type', 'PCT_Signature'])),
  245. "fipsinstall fails when the signature result is corrupted");
  246. }
  247. # corrupt an Asymmetric cipher test
  248. SKIP: {
  249. skip "Skipping Asymmetric RSA corruption test because of no rsa in this build", 1
  250. if disabled("rsa");
  251. ok(!run(app(['openssl', 'fipsinstall', '-out', 'fips.cnf', '-module', $infile,
  252. '-corrupt_desc', 'RSA_Encrypt',
  253. '-corrupt_type', 'KAT_AsymmetricCipher'])),
  254. "fipsinstall fails when the asymmetric cipher result is corrupted");
  255. }
  256. # 'local' ensures that this change is only done in this file.
  257. local $ENV{OPENSSL_CONF_INCLUDE} = abs2rel(curdir());
  258. ok(replace_parent_line_file('fips.cnf', 'fips_parent.cnf')
  259. && run(app(['openssl', 'fipsinstall', '-config', 'fips_parent.cnf'])),
  260. "verify fips provider loads from a configuration file");
  261. ok(replace_parent_line_file('fips_no_module_mac.cnf',
  262. 'fips_parent_no_module_mac.cnf')
  263. && !run(app(['openssl', 'fipsinstall',
  264. '-config', 'fips_parent_no_module_mac.cnf'])),
  265. "verify load config fail no module mac");
  266. SKIP: {
  267. run(test(["fips_version_test", "-config", $provconf, "<3.1.0"]),
  268. capture => 1, statusvar => \my $exit);
  269. skip "FIPS provider version doesn't support self test indicator", 3
  270. if !$exit;
  271. ok(replace_parent_line_file('fips_no_install_mac.cnf',
  272. 'fips_parent_no_install_mac.cnf')
  273. && !run(app(['openssl', 'fipsinstall',
  274. '-config', 'fips_parent_no_install_mac.cnf'])),
  275. "verify load config fail no install mac");
  276. ok(replace_parent_line_file('fips_bad_indicator.cnf',
  277. 'fips_parent_bad_indicator.cnf')
  278. && !run(app(['openssl', 'fipsinstall',
  279. '-config', 'fips_parent_bad_indicator.cnf'])),
  280. "verify load config fail bad indicator");
  281. ok(replace_parent_line_file('fips_bad_install_mac.cnf',
  282. 'fips_parent_bad_install_mac.cnf')
  283. && !run(app(['openssl', 'fipsinstall',
  284. '-config', 'fips_parent_bad_install_mac.cnf'])),
  285. "verify load config fail bad install mac");
  286. }
  287. ok(replace_parent_line_file('fips_bad_module_mac.cnf',
  288. 'fips_parent_bad_module_mac.cnf')
  289. && !run(app(['openssl', 'fipsinstall',
  290. '-config', 'fips_parent_bad_module_mac.cnf'])),
  291. "verify load config fail bad module mac");
  292. SKIP: {
  293. run(test(["fips_version_test", "-config", $provconf, "<3.1.0"]),
  294. capture => 1, statusvar => \my $exit);
  295. skip "FIPS provider version doesn't support self test indicator", 3
  296. if !$exit;
  297. my $stconf = "fipsmodule_selftest.cnf";
  298. ok(run(app(['openssl', 'fipsinstall', '-out', $stconf,
  299. '-module', $infile, '-self_test_onload'])),
  300. "fipsinstall config saved without self test indicator");
  301. ok(!run(app(['openssl', 'fipsinstall', '-in', $stconf,
  302. '-module', $infile, '-verify'])),
  303. "fipsinstall config verify fails without self test indicator");
  304. ok(run(app(['openssl', 'fipsinstall', '-in', $stconf,
  305. '-module', $infile, '-self_test_onload', '-verify'])),
  306. "fipsinstall config verify passes when self test indicator is not present");
  307. }
  308. SKIP: {
  309. run(test(["fips_version_test", "-config", $provconf, ">=3.1.0"]),
  310. capture => 1, statusvar => \my $exit);
  311. skip "FIPS provider version can run self tests on install", 1
  312. if !$exit;
  313. ok(!run(app(['openssl', 'fipsinstall', '-out', 'fips.cnf', '-module', $infile,
  314. '-provider_name', 'fips', '-mac_name', 'HMAC',
  315. '-macopt', 'digest:SHA256', '-macopt', "hexkey:$fipskey",
  316. '-section_name', 'fips_sect', '-self_test_oninstall',
  317. '-ems_check'])),
  318. "fipsinstall fails when attempting to run self tests on install");
  319. }
  320. ok(find_line_file('drbg-no-trunc-md = 0', 'fips.cnf') == 1,
  321. 'fipsinstall defaults to not banning truncated digests with DRBGs');
  322. ok(run(app(['openssl', 'fipsinstall', '-out', 'fips.cnf', '-module', $infile,
  323. '-provider_name', 'fips', '-mac_name', 'HMAC',
  324. '-macopt', 'digest:SHA256', '-macopt', "hexkey:$fipskey",
  325. '-section_name', 'fips_sect', '-no_drbg_truncated_digests'])),
  326. "fipsinstall knows about allowing truncated digests in DRBGs");
  327. ok(find_line_file('drbg-no-trunc-md = 1', 'fips.cnf') == 1,
  328. 'fipsinstall will allow option for truncated digests with DRBGs');
  329. ok(run(app(['openssl', 'fipsinstall', '-out', 'fips-pedantic.cnf',
  330. '-module', $infile, '-pedantic'])),
  331. "fipsinstall accepts -pedantic option");
  332. foreach my $o (@pedantic_okay) {
  333. ok(run(app(['openssl', 'fipsinstall', '-out', "fips-${o}.cnf",
  334. '-module', $infile, '-pedantic', "-${o}"])),
  335. "fipsinstall accepts -${o} after -pedantic option");
  336. }
  337. foreach my $o (@pedantic_fail) {
  338. ok(!run(app(['openssl', 'fipsinstall', '-out', 'fips_fail.cnf',
  339. '-module', $infile, '-pedantic', "-${o}"])),
  340. "fipsinstall disallows -${o} after -pedantic option");
  341. }