source: mod_gnutls/test/data/ocsp.py @ 33d812d

proxy-ticket
Last change on this file since 33d812d was 199acff, checked in by Fiona Klute <fiona.klute@…>, 8 months ago

ocsp.py: Log OCPS requests to stderr

With this the requests will appear in the server log via mod_cgi,
where tests can read and evaluate them.

  • Property mode set to 100755
File size: 3.9 KB
Line 
1#!/usr/bin/python3
2# Python 3 wrapper to use "openssl ocsp" as a simple OCSP responder
3#
4# Copyright 2020 Krista Karppinen, Fiona Klute
5#
6# Licensed under the Apache License, Version 2.0 (the "License"); you
7# may not use this file except in compliance with the License.  You
8# may obtain a copy of the License at
9#
10#      http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS,
14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
15# implied.  See the License for the specific language governing
16# permissions and limitations under the License.
17
18# This is a CGI script to run the OpenSSL OCSP responder from a web
19# server. The CGI environment must provide the following four
20# variables to configure the OCSP responder:
21#
22# CA_CERT: CA certificate of the CA that issued the certificates this
23# OCSP reponder should provide status information for
24#
25# OCSP_INDEX: CA index file in the format used by OpenSSL
26#
27# OCSP_CERT: Certificate that should be used to sign OCSP reponses
28# (either CA_CERT or a dedicated OCSP signer certificate, see RFC
29# 6960, Section 4.2.2.2)
30#
31# OCSP_KEY: Private key for OCSP_CERT
32#
33# Additionally, the OpenSSL binary to use can be configured through
34# the OPENSSL environment variable. If it is not set, the PATH will be
35# searched.
36
37from http import HTTPStatus
38import base64
39import os
40import shutil
41import subprocess
42import sys
43
44
45REQUEST_TYPE = 'application/ocsp-request'
46RESPONSE_TYPE = 'application/ocsp-response'
47
48
49def stdout(data):
50    sys.stdout.buffer.write(data)
51
52def stdout_line(line):
53    stdout(line.encode('utf-8'))
54    stdout(b'\n')
55
56def stdout_status(status, content_type='text/plain'):
57    stdout_line(f'Status: {status.value} {status.phrase}')
58    stdout_line(f'Content-Type: {content_type}\n')
59
60def stdout_response(status, response):
61    stdout_status(status, content_type=RESPONSE_TYPE)
62    stdout(response)
63
64
65def handle_get():
66    # GET OCSP requests are allowed by RFC 6960, Appendix A.1, but
67    # not implemented here. It should be possible to extract a GET
68    # request from the PATH_INFO CGI variable.
69    stdout_status(HTTPStatus.METHOD_NOT_ALLOWED)
70    stdout_line('OCSP GET request not implemented.')
71
72def handle_post():
73    content_type = os.getenv('CONTENT_TYPE')
74    content_length = os.getenv('CONTENT_LENGTH')
75    if content_type != REQUEST_TYPE or not content_length:
76        stdout_status(HTTPStatus.UNSUPPORTED_MEDIA_TYPE)
77        stdout_line(f'POST request must contain {REQUEST_TYPE} data.')
78        return
79
80    try:
81        req = sys.stdin.buffer.read(int(content_length))
82        print(f'Received OCSP request: \'{base64.b64encode(req).decode()}\'',
83              file=sys.stderr, flush=True)
84        openssl = os.getenv('OPENSSL') or shutil.which('openssl')
85        openssl_run = subprocess.run([openssl, 'ocsp',
86            '-index', os.getenv('OCSP_INDEX'),
87            '-CA', os.getenv('CA_CERT'),
88            '-rsigner', os.getenv('OCSP_CERT'),
89            '-rkey', os.getenv('OCSP_KEY'),
90            '-nmin', os.getenv('OCSP_VALID_MIN', '5'),
91            '-reqin', '-', '-respout', '-'],
92            input=req, capture_output=True)
93
94        if openssl_run.returncode == 0:
95            stdout_response(HTTPStatus.OK, openssl_run.stdout)
96            sys.stderr.buffer.write(openssl_run.stderr)
97        else:
98            raise Exception('openssl process exited with return code '
99                            f'{openssl_run.returncode}, stdout: '
100                            f'{openssl_run.stdout}, stderr: '
101                            f'{openssl_run.stderr}')
102    except:
103        stdout_status(HTTPStatus.INTERNAL_SERVER_ERROR)
104        raise
105
106
107if __name__ == '__main__':
108    method = os.getenv('REQUEST_METHOD')
109    if method == 'GET':
110        handle_get()
111    elif method == 'POST':
112        handle_post()
113    else:
114        stdout_status(HTTPStatus.METHOD_NOT_ALLOWED)
Note: See TracBrowser for help on using the repository browser.