1#!/usr/bin/env perl
2#
3# Copyright (C) 2012 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#      http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17
18#
19# This script parses the NIST PKI Test Suite test descriptions document
20# and creates a .java file with test cases.
21#
22
23use strict;
24
25my $enabled = 0;
26my $readingPath = 0;
27my $sectionName;
28my $testNumber;
29my $testName;
30my $pathEntry = "";
31my $expectedOutcome;
32my @pathEntries;
33
34my @usedFiles = ();
35
36my $delimiter = "\x{2022}";
37utf8::encode($delimiter);
38
39if ($#ARGV != 2) {
40    die "Usage: $0 <text-descriptions> <java-output> <used-files-output>";
41}
42
43open(DESC_FILE, "<", $ARGV[0]);
44open(OUTPUT_FILE, ">", $ARGV[1]);
45open(USED_FILES, ">", $ARGV[2]);
46
47sub trim($) {
48    my $s = shift;
49    $s =~ s/^\s+//g;
50    $s =~ s/\s+$//g;
51    return $s;
52}
53
54sub printTest() {
55    my @certNames;
56    my @crlNames;
57
58    foreach my $entry (@pathEntries) {
59        $entry =~ s/ //g;
60        $entry =~ s/-//g;
61        my @parts = split(/,/, $entry);
62        for my $part (@parts) {
63            if ($part =~ /CRL[0-9]*$/) {
64                my $crlName = $part . ".crl";
65                push(@crlNames, $crlName);
66                push(@usedFiles, "crls/" . $crlName);
67            } else {
68                my $certName = $part . ".crt";
69                push(@certNames, $certName);
70                push(@usedFiles, "certs/" . $certName);
71            }
72        }
73    }
74
75    print OUTPUT_FILE <<EOF;
76    /** NIST PKITS test ${testNumber} */
77    public void test${sectionName}_${testName}() throws Exception {
78EOF
79    print OUTPUT_FILE " " x 8 . "String trustAnchor = \"" . (shift @certNames) . "\";\n";
80
81    print OUTPUT_FILE <<EOF;
82
83        String[] certs = {
84EOF
85
86    # Print the CertPath in reverse order.
87    for (0..$#certNames) {
88        print OUTPUT_FILE " " x 16 . "\"${certNames[$#certNames - $_]}\",\n";
89    }
90    print OUTPUT_FILE <<EOF;
91        };
92
93        String[] crls = {
94EOF
95    foreach my $crlName (@crlNames) {
96        print OUTPUT_FILE " " x 16 . "\"${crlName}\",\n";
97    }
98    print OUTPUT_FILE <<EOF;
99        };
100
101EOF
102    if ($expectedOutcome) {
103        print OUTPUT_FILE <<EOF;
104        assertValidPath(trustAnchor, certs, crls);
105EOF
106    } else {
107        print OUTPUT_FILE <<EOF;
108        assertInvalidPath(trustAnchor, certs, crls);
109EOF
110    }
111
112        print OUTPUT_FILE <<EOF;
113    }
114
115EOF
116}
117
118sub stopReadingPath() {
119    if ($readingPath) {
120        if (defined($pathEntry) and $pathEntry ne "") {
121            push(@pathEntries, $pathEntry);
122            $pathEntry = "";
123        }
124
125        printTest();
126        @pathEntries = ();
127        $readingPath = 0;
128    }
129}
130
131
132while (<DESC_FILE>) {
133    chomp;
134
135    if ($_ =~ /^\s*4 Certification Path Validation Tests$/) {
136        $enabled = 1;
137        next;
138    }
139
140    #
141    # TODO: this script needs to be fixed to support the test cases in
142    # 4.8 to 4.12
143    #
144
145    if ($_ =~ /^\s*4\.8 Certificate Policies\s*$/) {
146        stopReadingPath();
147        $enabled = 0;
148
149        print OUTPUT_FILE " "x4 . "// skipping sections 4.8 to 4.12\n\n";
150        next;
151    }
152
153    if ($_ =~ /^\s*4\.13 Name Constraints\s*$/) {
154        $enabled = 1;
155        next;
156    }
157
158    if ($_ =~ /^\s*5 Relationship to Previous Test Suite\s*[^.]/) {
159        stopReadingPath();
160        $enabled = 0;
161        exit;
162    }
163
164    if (!$enabled) {
165        next;
166    }
167
168    if ($_ =~ /^\s*4\.[0-9]+ (.*)$/) {
169        stopReadingPath();
170        $sectionName = $1;
171        $sectionName =~ s/ //g;
172        $sectionName =~ s/-//g;
173    }
174
175    if ($_ =~ /^\s*(4\.[0-9]+\.[0-9]+) (.*)$/) {
176        stopReadingPath();
177        $testNumber = $1;
178        $testName = $2;
179        $testName =~ s/ //g;
180        $testName =~ s/-//g;
181    }
182
183    if ($_ =~ /Expected Result:.*(should validate|should not validate)/) {
184        if ($1 eq "should validate") {
185            $expectedOutcome = 1;
186        } else {
187            $expectedOutcome = 0;
188        }
189    } elsif ($_ =~ /Expected Result:/) {
190        die "Can not determine expected result for test:\n\t${testName}";
191    }
192
193    if ($_ =~ /^\s*Certification Path:/) {
194        $readingPath = 1;
195        next;
196    }
197
198    if ($readingPath) {
199        # Page number from the PDF
200        if (trim($_) =~ /^[0-9]+$/) {
201            do {
202                $_ = <DESC_FILE>;
203                if ($_ =~ /^\s*$/) {
204                    next;
205                }
206            } while (1);
207        }
208
209        if ($_ =~ /${delimiter}\s*(.*)$/u) {
210            if (defined($pathEntry) and $pathEntry ne "") {
211                push(@pathEntries, $pathEntry);
212            }
213            $pathEntry = trim($1);
214        } else {
215            if ($_ =~ /The certification path is composed of the following objects:(.*)$/) {
216                $pathEntry = trim($1);
217            } else {
218                $pathEntry .= trim($_);
219            }
220        }
221    }
222}
223
224print USED_FILES join("\n", keys %{{map{$_ => 1} @usedFiles}});
225
226close(DESC_FILE);
227close(OUTPUT_FILE);
228close(USED_FILES);
229