source: mod_gnutls/test/data/ocsp.py @ de81c0f

proxy-ticket
Last change on this file since de81c0f was de81c0f, checked in by Fiona Klute <fiona.klute@…>, 7 months ago

ocsp.py: Capture the OCSP request in a variable

This will be useful for logging later.

  • Property mode set to 100755
File size: 3.8 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 os
39import shutil
40import subprocess
41import sys
42
43
44REQUEST_TYPE = 'application/ocsp-request'
45RESPONSE_TYPE = 'application/ocsp-response'
46
47
48def stdout(data):
49    sys.stdout.buffer.write(data)
50
51def stdout_line(line):
52    stdout(line.encode('utf-8'))
53    stdout(b'\n')
54
55def stdout_status(status, content_type='text/plain'):
56    stdout_line(f'Status: {status.value} {status.phrase}')
57    stdout_line(f'Content-Type: {content_type}\n')
58
59def stdout_response(status, response):
60    stdout_status(status, content_type=RESPONSE_TYPE)
61    stdout(response)
62
63
64def handle_get():
65    # GET OCSP requests are allowed by RFC 6960, Appendix A.1, but
66    # not implemented here. It should be possible to extract a GET
67    # request from the PATH_INFO CGI variable.
68    stdout_status(HTTPStatus.METHOD_NOT_ALLOWED)
69    stdout_line('OCSP GET request not implemented.')
70
71def handle_post():
72    content_type = os.getenv('CONTENT_TYPE')
73    content_length = os.getenv('CONTENT_LENGTH')
74    if content_type != REQUEST_TYPE or not content_length:
75        stdout_status(HTTPStatus.UNSUPPORTED_MEDIA_TYPE)
76        stdout_line(f'POST request must contain {REQUEST_TYPE} data.')
77        return
78
79    try:
80        req = sys.stdin.buffer.read(int(content_length))
81        openssl = os.getenv('OPENSSL') or shutil.which('openssl')
82        openssl_run = subprocess.run([openssl, 'ocsp',
83            '-index', os.getenv('OCSP_INDEX'),
84            '-CA', os.getenv('CA_CERT'),
85            '-rsigner', os.getenv('OCSP_CERT'),
86            '-rkey', os.getenv('OCSP_KEY'),
87            '-nmin', os.getenv('OCSP_VALID_MIN', '5'),
88            '-reqin', '-', '-respout', '-'],
89            input=req, capture_output=True)
90
91        if openssl_run.returncode == 0:
92            stdout_response(HTTPStatus.OK, openssl_run.stdout)
93            sys.stderr.buffer.write(openssl_run.stderr)
94        else:
95            raise Exception('openssl process exited with return code '
96                            f'{openssl_run.returncode}, stdout: '
97                            f'{openssl_run.stdout}, stderr: '
98                            f'{openssl_run.stderr}')
99    except:
100        stdout_status(HTTPStatus.INTERNAL_SERVER_ERROR)
101        raise
102
103
104if __name__ == '__main__':
105    method = os.getenv('REQUEST_METHOD')
106    if method == 'GET':
107        handle_get()
108    elif method == 'POST':
109        handle_post()
110    else:
111        stdout_status(HTTPStatus.METHOD_NOT_ALLOWED)
Note: See TracBrowser for help on using the repository browser.