Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add command-based response mode #62

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ python https server that you can inspect for yourself before you run it.
* Signing script
* [How to use the signing script](#how-to-use-the-signing-script)
* [Example use of the signing script](#example-use-of-the-signing-script)
* [Automating the domain ownership challenge](#automating-the-domain-ownership-challenge)
* [How to use the signed https certificate](#how-to-use-the-signed-https-certificate)
* [Demo](#demo)
* Revocation script
Expand Down Expand Up @@ -268,6 +269,35 @@ KeyboardInterrupt
[email protected]:~$
```

##Automating the domain ownership challenge

If you don't want to manually add the challenge files to your webserver, you
can also set up a command to run when `sign_csr.py` wants to add a file to your
web server. Example scripts are included. First, you'll need to set up a
directory on the web server (e.g. /var/www/acme). You can use something like
the following to achieve that:
```
ProxyPass /.well-known/acme-challenge/ !
SetEnvIf Request_URI ^/.well-known/acme-challenge/ no-jk
Alias /.well-known/acme-challenge/ /var/www/acme/
<Directory "/var/www/acme">
Require all granted
</Directory>
...
<VirtualHost *:80>
...
<IfModule mod_rewrite.c>
RewriteRule ^/.well-known/acme-challenge/ - [L]
</IfModule>
...
</VirtualHost>
```

Then just run sign_csr.py with the `--cmd-add` and `--cmd-rm` options:
```
user@hostname:~$ python sign_csr.py --public-key user.pub --cmd-add ./acme_add --cmd-rm ./acme_rm domain.csr > signed.crt
```

##How to use the signed https certificate

The signed https certificate that is output by this script can be used along
Expand Down
9 changes: 9 additions & 0 deletions acme_add
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/bin/bash

domain="$1"
filename="$2"
contents="$3"

if [ "$contents" ]; then
exec /usr/bin/ssh -o 'StrictHostKeyChecking no' "$domain" /usr/bin/sudo /usr/bin/tee /var/www/acme/"$filename" <<< "$contents" > /dev/null
fi
8 changes: 8 additions & 0 deletions acme_rm
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/bin/bash

domain="$1"
filename="$2"

if [ "$filename" ]; then
exec /usr/bin/ssh -o 'StrictHostKeyChecking no' "$domain" /usr/bin/sudo /bin/rm /var/www/acme/"$filename"
fi
Empty file modified revoke_crt.py
100644 → 100755
Empty file.
31 changes: 27 additions & 4 deletions sign_csr.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,14 @@
hashlib, tempfile, re, copy, textwrap


def sign_csr(pubkey, csr, email=None, file_based=False):
SHOW_COMMANDS = True

def run_cmd(arglist):
if SHOW_COMMANDS:
sys.stderr.write(" ".join(arglist) + "\n")
return subprocess.check_call(arglist)

def sign_csr(pubkey, csr, email=None, file_based=False, cmd_add=None, cmd_rm=None):
"""Use the ACME protocol to get an ssl certificate signed by a
certificate authority.

Expand Down Expand Up @@ -262,6 +269,7 @@ def _b64(b):
"file_name": test_file_name,
"sig": test_file_sig,
"sig_name": test_file_sig_name,
"token": challenge['token'],
})

# challenge response for server
Expand Down Expand Up @@ -291,8 +299,15 @@ def _b64(b):
tests[n]['sig64'] = _b64(tests[n]['sig'].read())

# Step 11: Ask the user to host the token on their server
if cmd_add:
sys.stderr.write("\nSTEP 4: Adding signatures to server.\n\n")
for n, i in enumerate(ids):
if file_based:
if cmd_add:
try:
run_cmd([cmd_add, i['domain'], tests[n]['token'], responses[n]['data']])
except subprocess.CalledProcessError:
sys.stderr.write("An error occurred adding signatures to server. Continuing anyway.\n")
elif file_based:
sys.stderr.write("""\
STEP {0}: Please update your server to serve the following file at this URL:

Expand Down Expand Up @@ -397,7 +412,13 @@ def _b64(b):
# Step 15: Convert the signed cert from DER to PEM
sys.stderr.write("Certificate signed!\n")

if file_based:
if cmd_rm:
try:
for n, i in enumerate(ids):
run_cmd([cmd_rm, i['domain'], tests[n]['token']])
except subprocess.CalledProcessError:
sys.stderr.write("An error occurred removing signatures from server. Continuing anyway.\n")
elif file_based:
sys.stderr.write("You can remove the acme-challenge file from your webserver now.\n")
else:
sys.stderr.write("You can stop running the python command on your server (Ctrl+C works).\n")
Expand Down Expand Up @@ -440,9 +461,11 @@ def _b64(b):
parser.add_argument("-p", "--public-key", required=True, help="path to your account public key")
parser.add_argument("-e", "--email", default=None, help="contact email, default is webmaster@<shortest_domain>")
parser.add_argument("-f", "--file-based", action='store_true', help="if set, a file-based response is used")
parser.add_argument("-c", "--cmd-add", default=None, help="if set, 'command domain filename contents' will be called to add the challenge file to the web server")
parser.add_argument("-r", "--cmd-rm", default=None, help="if set, 'command domain filename' is called to remove the file from the web server")
parser.add_argument("csr_path", help="path to your certificate signing request")

args = parser.parse_args()
signed_crt = sign_csr(args.public_key, args.csr_path, email=args.email, file_based=args.file_based)
signed_crt = sign_csr(args.public_key, args.csr_path, email=args.email, file_based=args.file_based, cmd_add=args.cmd_add, cmd_rm=args.cmd_rm)
sys.stdout.write(signed_crt)