xref: /openbsd-src/regress/lib/libcrypto/man/check_complete.pl (revision 33885c32518568087b794e9d76f129869894d7fd)
1#!/usr/bin/perl
2#
3# Copyright (c) 2021 Ingo Schwarze <schwarze@openbsd.org>
4#
5# Permission to use, copy, modify, and distribute this software for any
6# purpose with or without fee is hereby granted, provided that the above
7# copyright notice and this permission notice appear in all copies.
8#
9# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
17use strict;
18use warnings;
19
20my %internal = (
21    asn1 => [qw(
22	ASN1_ENCODING
23	ASN1_STRING_FLAG_CONT
24	ASN1_STRING_FLAG_MSTRING ASN1_STRING_FLAG_NDEF
25	CHARTYPE_FIRST_ESC_2253 CHARTYPE_LAST_ESC_2253 CHARTYPE_PRINTABLESTRING
26    )],
27    bn => [qw(
28	BN_BITS BN_BITS4 BN_BYTES
29	BN_DEC_CONV BN_DEC_FMT1 BN_DEC_FMT2 BN_DEC_NUM BN_LLONG BN_LONG
30	BN_MASK2 BN_MASK2h BN_MASK2h1 BN_MASK2l
31	BN_TBIT BN_ULLONG
32    )],
33    evp => [qw(
34	ASN1_PKEY_CTRL_CMS_ENVELOPE ASN1_PKEY_CTRL_CMS_RI_TYPE
35	ASN1_PKEY_CTRL_CMS_SIGN
36	dh_st dsa_st ec_key_st
37	EVP_MD_CTRL_ALG_CTRL
38	EVP_MD_CTX_FLAG_CLEANED EVP_MD_CTX_FLAG_REUSE
39	EVP_PKEY_ALG_CTRL
40	EVP_PKEY_CTRL_CMS_DECRYPT EVP_PKEY_CTRL_CMS_ENCRYPT
41	EVP_PKEY_CTRL_CMS_SIGN
42	EVP_PKEY_CTRL_DIGESTINIT
43	EVP_PKEY_CTRL_PEER_KEY
44	EVP_PKEY_CTRL_PKCS7_DECRYPT EVP_PKEY_CTRL_PKCS7_ENCRYPT
45	EVP_PKEY_CTRL_PKCS7_SIGN
46	rsa_st
47    )],
48    x509_vfy => [qw(
49	X509_VERIFY_PARAM_ID
50    )]
51);
52
53my %obsolete = (
54    asn1 => [qw(
55	ASN1_dup ASN1_d2i_bio ASN1_d2i_bio_of ASN1_d2i_fp ASN1_d2i_fp_of
56	ASN1_i2d_bio ASN1_i2d_bio_of ASN1_i2d_bio_of_const
57	ASN1_i2d_fp ASN1_i2d_fp_of ASN1_i2d_fp_of_const
58	ASN1_LONG_UNDEF
59	BIT_STRING_BITNAME
60	V_ASN1_PRIMATIVE_TAG
61	X509_algor_st
62    )],
63    bio => [qw(
64	asn1_ps_func
65	BIO_C_GET_PROXY_PARAM BIO_C_GET_SOCKS
66	BIO_C_SET_PROXY_PARAM BIO_C_SET_SOCKS
67	BIO_get_no_connect_return BIO_get_proxies
68	BIO_get_proxy_header BIO_get_url
69	BIO_set_filter_bio BIO_set_no_connect_return BIO_set_proxies
70	BIO_set_proxy_cb BIO_set_proxy_header BIO_set_url
71    )],
72    bn => [qw(
73	BN_HEX_FMT1 BN_HEX_FMT2 BN_MASK
74    )],
75    evp => [qw(
76	EVP_CIPH_FLAG_FIPS EVP_CIPH_FLAG_NON_FIPS_ALLOW
77	EVP_CTRL_AEAD_SET_MAC_KEY EVP_CTRL_AEAD_TLS1_AAD
78	EVP_CTRL_GET_RC5_ROUNDS EVP_CTRL_GOST_SET_SBOX
79	EVP_CTRL_PBE_PRF_NID EVP_CTRL_SET_RC5_ROUNDS
80	EVP_MD_CTRL_DIGALGID EVP_MD_CTRL_GOST_SET_SBOX EVP_MD_CTRL_SET_KEY
81	EVP_MD_CTX_FLAG_NON_FIPS_ALLOW EVP_MD_CTX_FLAG_PAD_MASK
82	EVP_MD_CTX_FLAG_PAD_PKCS1 EVP_MD_CTX_FLAG_PAD_PSS
83	EVP_MD_FLAG_DIGALGID_MASK
84	EVP_PBE_KEYGEN
85	EVP_PKEY_CTRL_SET_IV
86	EVP_PKEY_GOSTIMIT EVP_PKEY_GOSTR01
87	EVP_PKEY_GOSTR12_256 EVP_PKEY_GOSTR12_512
88	EVP_PKEY_MO_DECRYPT EVP_PKEY_MO_ENCRYPT
89	EVP_PKEY_MO_SIGN EVP_PKEY_MO_VERIFY
90    )],
91);
92
93my %postponed = (
94    asn1 => [qw(
95	ASN1_ITEM_EXP ASN1_ITEM_ptr ASN1_ITEM_ref ASN1_ITEM_rptr
96	ASN1_TEMPLATE ASN1_TLC
97	CHECKED_D2I_OF CHECKED_I2D_OF CHECKED_NEW_OF
98	CHECKED_PPTR_OF CHECKED_PTR_OF
99	DECLARE_ASN1_ALLOC_FUNCTIONS DECLARE_ASN1_ALLOC_FUNCTIONS_name
100	DECLARE_ASN1_ENCODE_FUNCTIONS DECLARE_ASN1_ENCODE_FUNCTIONS_const
101	DECLARE_ASN1_FUNCTIONS DECLARE_ASN1_FUNCTIONS_const
102	DECLARE_ASN1_FUNCTIONS_fname DECLARE_ASN1_FUNCTIONS_name
103	DECLARE_ASN1_ITEM
104	DECLARE_ASN1_NDEF_FUNCTION
105	DECLARE_ASN1_PRINT_FUNCTION DECLARE_ASN1_PRINT_FUNCTION_fname
106	DECLARE_ASN1_SET_OF
107	D2I_OF
108	IMPLEMENT_ASN1_SET_OF
109	I2D_OF I2D_OF_const
110	TYPEDEF_D2I_OF TYPEDEF_D2I2D_OF TYPEDEF_I2D_OF
111    )],
112    x509 => [qw(
113	NETSCAPE_SPKAC NETSCAPE_SPKI PBEPARAM
114    )]
115);
116
117my $MANW = 'man -M /usr/share/man -w';
118my $srcdir = '/usr/src/lib/libcrypto/man';
119my $hfile = '/usr/include/openssl';
120
121my $in_cplusplus = 0;
122my $in_comment = 0;
123my $in_define = 0;
124my $in_function = 0;
125my $in_struct = 0;
126my $in_typedef_struct = 0;
127my %expect_undoc = ();
128my %found_undoc = ();
129my $verbose = 0;
130
131if (defined $ARGV[0] && $ARGV[0] eq '-v') {
132	$verbose = 1;
133	shift @ARGV;
134}
135$#ARGV == 0 or die "usage: $0 [-v] headername";
136$hfile .= "/$ARGV[0].h";
137open my $in_fh, '<', $hfile or die "$hfile: $!";
138
139$expect_undoc{$_} = 1 foreach @{$internal{$ARGV[0]}};
140$expect_undoc{$_} = 1 foreach @{$obsolete{$ARGV[0]}};
141$expect_undoc{$_} = 1 foreach @{$postponed{$ARGV[0]}};
142
143while (<$in_fh>) {
144try_again:
145	chomp;
146	my $line = $_;
147
148	# C language comments.
149
150	if ($in_comment) {
151		unless (s/.*?\*\///) {
152			print "-- $line\n" if $verbose;
153			next;
154		}
155		$in_comment = 0;
156	}
157	while (/\/\*/) {
158		s/\s*\/\*.*?\*\/// and next;
159		s/\s*\/\*.*// and $in_comment = 1;
160	}
161
162	# End C++ stuff.
163
164	if ($in_cplusplus) {
165		/^#endif$/ and $in_cplusplus = 0;
166		print "-- $line\n" if $verbose;
167		next;
168	}
169
170	# End declarations of structs.
171
172	if ($in_struct) {
173		if (/^\s*union\s+{$/) {
174			print "-s $line\n" if $verbose;
175			$in_struct++;
176			next;
177		}
178		unless (s/^\s*\}//) {
179			print "-s $line\n" if $verbose;
180			next;
181		}
182		if (--$in_struct && /^\s+\w+;$/) {
183			print "-s $line\n" if $verbose;
184			next;
185		}
186		unless ($in_typedef_struct) {
187			/^\s*;$/ or die "at end of struct: $_";
188			print "-s $line\n" if $verbose;
189			next;
190		}
191		$in_typedef_struct = 0;
192		my ($id) = /^\s*(\w+);$/
193		    or die "at end of typedef struct: $_";
194		unless (system "$MANW -k 'Vt~^$id\$' > /dev/null 2>&1") {
195			print "Vt $line\n" if $verbose;
196			next;
197		}
198		if ($expect_undoc{$id}) {
199			print "V- $line\n" if $verbose;
200			$found_undoc{$id} = 1;
201			next;
202		}
203		if ($verbose) {
204			print "XX $line\n";
205		} else {
206			warn "not found: typedef struct $id";
207		}
208		next;
209	}
210
211	# End macro definitions.
212
213	if ($in_define) {
214		/\\$/ or $in_define = 0;
215		print "-d $line\n" if $verbose;
216		next;
217	}
218
219	# End function declarations.
220
221	if ($in_function) {
222		/^\s/ or die "function arguments not indented: $_";
223		/\);$/ and $in_function = 0;
224		print "-f $line\n" if $verbose;
225		next;
226	}
227
228	# Begin C++ stuff.
229
230	if (/^#ifdef\s+__cplusplus$/) {
231		$in_cplusplus = 1;
232		print "-- $line\n" if $verbose;
233		next;
234	}
235
236	# Uninteresting lines.
237
238	if (/^\s*$/ ||
239	    /^DECLARE_STACK_OF\(\w+\)$/ ||
240	    /^DECLARE_PKCS12_STACK_OF\(\w+\)$/ ||
241	    /^TYPEDEF_D2I2D_OF\(\w+\);$/ ||
242	    /^#define __bounded__\(\w+, \w+, \w+\)$/ ||
243	    /^#define HEADER_\w+_H$/ ||
244	    /^#endif$/ ||
245	    /^#else$/ ||
246	    /^#error/ ||
247	    /^extern\s+const\s+ASN1_ITEM\s+\w+_it;$/ ||
248	    /^#\s*include\s/ ||
249	    /^#ifn?def\s/ ||
250	    /^#if !?defined/ ||
251	    /^#undef\s+BN_LLONG$/) {
252		print "-- $line\n" if $verbose;
253		next;
254	}
255
256	# Begin declarations of structs.
257
258	if (/^(typedef )?(?:struct|enum)(?: \w+)? \{$/) {
259		$in_struct = 1;
260		$1 and $in_typedef_struct = 1;
261		print "-s $line\n" if $verbose;
262		next;
263	}
264
265	# Handle macros.
266
267	if (my ($id) = /^#\s*define\s+(\w+)\s+\S/) {
268		/\\$/ and $in_define = 1;
269		if ($id eq 'BN_ULONG' &&
270		    not system "$MANW -k 'Vt~^$id\$' > /dev/null 2>&1") {
271			print "Vt $line\n" if $verbose;
272			next;
273		}
274		unless (system "$MANW -k 'Dv~^$id\$' > /dev/null 2>&1") {
275			print "Dv $line\n" if $verbose;
276			next;
277		}
278		unless (system "$MANW $id > /dev/null 2>&1") {
279			print "Fn $line\n" if $verbose;
280			next;
281		}
282		unless (system qw/grep -qR/, '^\.\\\\" .*\<' . $id . '\>',
283		    "$srcdir/") {
284			print "D- $line\n" if $verbose;
285			next;
286		}
287		if ($id =~ /^ASN1_PCTX_FLAGS_\w+$/) {
288			print "D- $line\n" if $verbose;
289			next;
290		}
291		if ($id =~ /^(?:ASN1|BIO|BN|EVP|X509(?:V3)?)_[FR]_\w+$/) {
292			print "D- $line\n" if $verbose;
293			next;
294		}
295		if ($id =~ /^X509_V_ERR_\w+$/) {
296			print "D- $line\n" if $verbose;
297			next;
298		}
299		if ($id =~ /^(?:SN|LN|NID|OBJ)_\w+$/) {
300			print "D- $line\n" if $verbose;
301			next;
302		}
303		if ($expect_undoc{$id}) {
304			print "D- $line\n" if $verbose;
305			$found_undoc{$id} = 1;
306			next;
307		}
308		if ($verbose) {
309			print "XX $line\n";
310		} else {
311			warn "not found: #define $id";
312		}
313		next;
314	}
315	if (my ($id) = /^#\s*define\s+(\w+)\(/) {
316		/\\$/ and $in_define = 1;
317		unless (system "$MANW $id > /dev/null 2>&1") {
318			print "Fn $line\n" if $verbose;
319			next;
320		}
321		unless (system qw/grep -qR/, '^\.\\\\" .*\<' . $id . '\>',
322		    "$srcdir/") {
323			print "F- $line\n" if $verbose;
324			next;
325		}
326		if ($expect_undoc{$id}) {
327			print "F- $line\n" if $verbose;
328			$found_undoc{$id} = 1;
329			next;
330		}
331		if ($verbose) {
332			print "XX $line\n";
333		} else {
334			warn "not found: #define $id()";
335		}
336		next;
337	}
338	if (my ($id) = /^#\s*define\s+(\w+)$/) {
339		if ($expect_undoc{$id}) {
340			print "-- $line\n" if $verbose;
341			$found_undoc{$id} = 1;
342			next;
343		}
344		if ($verbose) {
345			print "XX $line\n";
346		} else {
347			warn "not found: #define $id";
348		}
349		next;
350	}
351
352	# Handle global variables.
353
354	if (my ($id) = /^extern\s+int\s+(\w+);$/) {
355		unless (system "$MANW -k 'Va~^$id\$' > /dev/null 2>&1") {
356			print "Va $line\n" if $verbose;
357			next;
358		}
359		if ($verbose) {
360			print "XX $line\n";
361		} else {
362			warn "not found: extern int $id";
363		}
364		next;
365	}
366
367	# Handle variable type declarations.
368
369	if (my ($id) = /^struct\s+(\w+);$/) {
370		unless (system "$MANW -k 'Vt~^$id\$' > /dev/null 2>&1") {
371			print "Vt $line\n" if $verbose;
372			next;
373		}
374		if ($expect_undoc{$id}) {
375			print "V- $line\n" if $verbose;
376			$found_undoc{$id} = 1;
377			next;
378		}
379		if ($verbose) {
380			print "XX $line\n";
381		} else {
382			warn "not found: struct $id";
383		}
384		next;
385	}
386
387	if (my ($id) = /^typedef\s+(?:const\s+)?(?:struct\s+)?\S+\s+(\w+);$/) {
388		unless (system "$MANW -k 'Vt~^$id\$' > /dev/null 2>&1") {
389			print "Vt $line\n" if $verbose;
390			next;
391		}
392		if ($expect_undoc{$id}) {
393			print "V- $line\n" if $verbose;
394			$found_undoc{$id} = 1;
395			next;
396		}
397		if ($verbose) {
398			print "XX $line\n";
399		} else {
400			warn "not found: typedef $id";
401		}
402		next;
403	}
404
405	if (my ($id) =/^typedef\s+\w+(?:\s+\*)?\s+\(\*(\w+)\)\(/) {
406		/\);$/ or $in_function = 1;
407		unless (system "$MANW $id > /dev/null 2>&1") {
408			print "Fn $line\n" if $verbose;
409			next;
410		}
411		if ($verbose) {
412			print "XX $line\n";
413		} else {
414			warn "not found: function type (*$id)()";
415		}
416		next;
417	}
418
419	# Handle function declarations.
420
421	if (/^\w+(?:\(\w+\))?(?:\s+\w+)*\s+(?:\(?\*\s*)?(\w+)\(/) {
422		my $id = $1;
423		/\);$/ or $in_function = 1;
424		unless (system "$MANW $id > /dev/null 2>&1") {
425			print "Fn $line\n" if $verbose;
426			next;
427		}
428		# These functions are still provided by OpenSSL
429		# and still used by the Python test suite,
430		# but intentionally undocumented because nothing
431		# else uses them according to tb@, Dec 3, 2021.
432		if ($id =~ /NETSCAPE_(?:CERT_SEQUENCE|SPKAC|SPKI)/) {
433			print "F- $line\n" if $verbose;
434			next;
435		}
436		unless (system qw/grep -qR/, '^\.\\\\" .*\<' . $id . '\>',
437		    "$srcdir/") {
438			print "F- $line\n" if $verbose;
439			next;
440		}
441		if ($expect_undoc{$id}) {
442			print "F- $line\n" if $verbose;
443			$found_undoc{$id} = 1;
444			next;
445		}
446		if ($id =~ /^ASN1_PCTX_\w+$/) {
447			print "F- $line\n" if $verbose;
448			next;
449		}
450		if ($verbose) {
451			print "XX $line\n";
452		} else {
453			warn "not found: function $id()";
454		}
455		next;
456	}
457	if (/^int$/) {
458		$_ .= ' ' . <$in_fh>;
459		goto try_again;
460	}
461	if (/ \*$/) {
462		$_ .= <$in_fh>;
463		goto try_again;
464	}
465	# The name of the function return type is so long
466	# that it requires a line break afterwards.
467	if (/^\w{30,}$/) {
468		my $next_line = <$in_fh>;
469		if ($next_line =~ /^ {4}\w/) {
470			$_ .= $next_line;
471			goto try_again;
472		}
473	}
474	die "parse error: $_";
475}
476close $in_fh;
477foreach (keys %expect_undoc) {
478	warn "expected as undocumented but not found: $_"
479	    unless $found_undoc{$_};
480}
481exit 0;
482