Imported Upstream version 1.0.0
[platform/upstream/nghttp2.git] / third-party / h2o / fetch-ocsp-response
1 #! /bin/sh
2 exec perl -x $0 "$@"
3 #! perl
4
5 # Copyright (c) 2015 DeNA Co., Ltd.
6 #
7 # Permission is hereby granted, free of charge, to any person obtaining a copy
8 # of this software and associated documentation files (the "Software"), to
9 # deal in the Software without restriction, including without limitation the
10 # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
11 # sell copies of the Software, and to permit persons to whom the Software is
12 # furnished to do so, subject to the following conditions:
13 #
14 # The above copyright notice and this permission notice shall be included in
15 # all copies or substantial portions of the Software.
16 #
17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
23 # IN THE SOFTWARE.
24
25 use strict;
26 use warnings;
27 use File::Temp qw(tempdir);
28 use Getopt::Long;
29
30 # from sysexits.h
31 use constant EX_TEMPFAIL => 75;
32
33 my ($issuer_fn, $opt_help);
34 my $openssl_cmd = 'openssl';
35
36 GetOptions(
37     "issuer=s"   => \$issuer_fn,
38     "openssl=s", => \$openssl_cmd,
39     help         => \$opt_help,
40 ) or exit(1);
41 if ($opt_help) {
42     print << "EOT";
43 Usage: $0 [<options>] <certificate-file>
44
45 Options:
46   --issuer <file>  issuer certificate (if omitted, is extracted from the
47                    certificate chain)
48   --openssl <cmd>  openssl command to use (default: "openssl")
49   --help           prints this help
50
51 The command issues an OCSP request for given server certificate, verifies the
52 response and prints the resulting DER.
53
54 The command exits 0 if successful, or 75 (EX_TEMPFAIL) on temporary error.
55 Other exit codes may be returned in case of hard errors.
56
57 EOT
58     exit(0);
59 }
60
61 die "no certificate file\n"
62     if @ARGV == 0;
63 my $cert_fn = shift @ARGV;
64
65 my $tempdir = tempdir(CLEANUP => 1);
66
67 my $openssl_version = run_openssl("version");
68 chomp $openssl_version;
69 print STDERR "fetch-ocsp-response (using $openssl_version)\n";
70
71 # obtain ocsp uri
72 my $ocsp_uri = run_openssl("x509 -in $cert_fn -noout -ocsp_uri");
73 chomp $ocsp_uri;
74 die "failed to extract ocsp URI from $cert_fn\n"
75     if $ocsp_uri !~ m{^https?://};
76 my($ocsp_host) = $ocsp_uri =~ m{^https?://([^/:]+)};
77
78 # save issuer certificate
79 if (! defined $issuer_fn) {
80     my $chain = read_file($cert_fn);
81     $chain =~ m{-----END CERTIFICATE-----.*?(-----BEGIN CERTIFICATE-----.*?-----END CERTIFICATE-----)}s
82         or die "--issuer option was not used, and failed to extract issuer certificate from the certificate\n";
83     $issuer_fn = "$tempdir/issuer.crt";
84     write_file($issuer_fn, "$1\n");
85 }
86
87 # obtain response (without verification)
88 print STDERR "sending OCSP request to $ocsp_uri\n";
89 my $resp = run_openssl(
90     "ocsp -issuer $issuer_fn -cert $cert_fn -url $ocsp_uri"
91     . ($openssl_version =~ /^OpenSSL 1\./is ? " -header Host $ocsp_host" : "")
92     . " -noverify -respout $tempdir/resp.der " . join(' ', @ARGV),
93     1,
94 );
95 print STDERR $resp;
96
97 # verify the response
98 print STDERR "verifying the response signature\n";
99 my $success;
100 for my $args (
101     # try from exotic options
102     "-VAfile $issuer_fn",                               # for comodo
103     "-partial_chain -trusted_first -CAfile $issuer_fn", # these options are only available in OpenSSL >= 1.0.2
104     "-CAfile $issuer_fn",                               # for OpenSSL <= 1.0.1
105 ) {
106     if (system("$openssl_cmd ocsp -respin $tempdir/resp.der $args > $tempdir/verify.out 2>&1") == 0) {
107         print STDERR "verify OK (used: $args)\n";
108         $success = 1;
109         last;
110     }
111 }
112 if (! $success) {
113     print STDERR read_file("$tempdir/verify.out");
114     tempfail("failed to verify the response\n");
115 }
116
117 # success
118 print read_file("$tempdir/resp.der");
119 exit 0;
120
121 sub run_openssl {
122     my ($args, $tempfail) = @_;
123     open my $fh, "-|", "$openssl_cmd $args"
124         or die "failed to invoke $openssl_cmd:$!";
125     my $resp = do { local $/; <$fh> };
126     close $fh
127         or ($tempfail ? \&tempfail : \&die)->("OpenSSL exitted abnormally: $openssl_cmd $args:$!");
128     $resp;
129 }
130
131 sub read_file {
132     my $fn = shift;
133     open my $fh, "<", $fn
134         or die "failed to open file:$fn:$!";
135     local $/;
136     <$fh>;
137 }
138
139 sub write_file {
140     my ($fn, $data) = @_;
141     open my $fh, ">", $fn
142         or die "failed to open file:$fn:$!";
143     print $fh $data;
144     close $fh;
145 }
146
147 sub tempfail {
148     print STDERR @_;
149     exit EX_TEMPFAIL;
150 }