diff options
Diffstat (limited to 'README.md')
-rw-r--r-- | README.md | 315 |
1 files changed, 146 insertions, 169 deletions
@@ -48,14 +48,34 @@ but they do fantastic work. * openssl * python -You will also need to transfer the test key and certificate to your server -temporarily. The command printed out uses `scp` for that, but you can use any -secure transfer program. - ##How to use the script -You run the script using python and passing in the path to your CSR (i.e. -`python sign_csr.py /path/to/cert.csr`). The path can be relative or absolute. +First, you need to generate an user account key for Let's Encrypt. +This is the key that you use to register with Let's Encrypt. If you +already have user account key with Let's Encrypt, you can skip this +step. + +```sh +openssl genrsa 4096 > user.key +openssl rsa -in user.key -pubout > user.pub +``` + +Second, you need to generate the domain key and a certificate request. +This is the key that you will get signed for free for your domain (replace +"example.com" with the domain you own). If you already have a domain key +and CSR for your domain, you can skip this step. + +```sh +openssl genrsa 4096 > domain.key +openssl req -new -sha256 -key domain.key -subj "/CN=example.com" > domain.csr +``` + +Third, you run the script using python and passing in the path to your user +account public key and the domain CSR. The paths can be relative or absolute. + +```sh +python sign_csr.py user.pub domain.csr > signed.crt +``` When you run the script, it will ask you do do some manual commands. It has to ask you to do these because it doesn't know your private key or have access to @@ -69,203 +89,162 @@ or continue the script before you run the commands, those test files will be destroyed before they can be used correctly (and you'll have to run the script again). -The `test_*` files are temporary files automatically generated by the script and -will be destroyed when the script stops. They only contain test certificates and -signatures. +The `*.json` and `*.sig` files are temporary files automatically generated by +the script and will be destroyed when the script stops. They only contain the +protocol requests and signatures. They do NOT contain your private keys +because this script does not have access to your private keys. ###Help text ``` user@hostname:~$ python sign_csr.py --help -usage: sign_csr.py [-h] csr_path +usage: sign_csr.py [-h] pubkey_path csr_path Get a SSL certificate signed by a Let's Encrypt (ACME) certificate authority and output that signed certificate. You do NOT need to run this script on your -server and this script does not ask for your private key. It will print out +server and this script does not ask for your private keys. It will print out commands that you need to run with your private key or on your server as root, which gives you a chance to review the commands instead of trusting this script. +NOTE: YOUR ACCOUNT KEY NEEDS TO BE DIFFERENT FROM YOUR DOMAIN KEY. + Prerequisites: * openssl * python -Example: Generate a key, create a csr, and have it signed. +Example: Generate an account keypair, a domain key and csr, and have the domain csr signed. -------------- -$ openssl genrsa -out priv.key 4096 -$ openssl req -new -subj "/CN=test4.byofs.com" -key priv.key -out cert.csr -$ python sign_csr.py cert.csr > signed.crt +$ openssl genrsa 4096 > user.key +$ openssl rsa -in user.key -pubout > user.pub +$ openssl genrsa 4096 > domain.key +$ openssl req -new -sha256 -key domain.key -subj "/CN=example.com" > domain.csr +$ python sign_csr.py user.pub domain.csr > signed.crt -------------- positional arguments: - csr_path path to certificate signing request + pubkey_path path to your account public key + csr_path path to your certificate signing request optional arguments: - -h, --help show this help message and exit -user@hostname:~$ + -h, --help show this help message and exit +user@hostname:~$ ``` ##Example Use -###Commands (without output) -```sh -#Generate a private key -openssl genrsa -out priv.key 4096 - -#Generate a CSR -openssl req -new -sha256 -key priv.key -out cert.csr - -#Download the script in this repo -wget https://raw.githubusercontent.com/diafygi/letsencrypt-nosudo/master/sign_csr.py - -#Get Let's Encrypt to sign the CSR -python sign_csr.py cert.csr > signed.crt - -#Output the CSR so you can see it -cat signed.crt +###Commands (what you do in your main terminal window) ``` - -###Commands (with full output) -``` -user@hostname:~$ openssl genrsa -out priv.key 4096 +user@hostname:~$ openssl genrsa 4096 > user.key Generating RSA private key, 4096 bit long modulus -....................................................................++ -...........................................................................++ +.............................................................................................................................................................................++ +....................................................++ e is 65537 (0x10001) -user@hostname:~$ openssl req -new -sha256 -key priv.key -out cert.csr -You are about to be asked to enter information that will be incorporated -into your certificate request. -What you are about to enter is what is called a Distinguished Name or a DN. -There are quite a few fields but you can leave some blank -For some fields there will be a default value, -If you enter '.', the field will be left blank. ------ -Country Name (2 letter code) [AU]:US -State or Province Name (full name) [Some-State]:California -Locality Name (eg, city) []:Oakland -Organization Name (eg, company) [Internet Widgits Pty Ltd]:Daylightpirates -Organizational Unit Name (eg, section) []: -Common Name (e.g. server FQDN or YOUR name) []:letsencrypt.daylightpirates.org -Email Address []:info@daylightpirates.org - -Please enter the following 'extra' attributes -to be sent with your certificate request -A challenge password []: -An optional company name []: -user@hostname:~$ wget https://raw.githubusercontent.com/diafygi/letsencrypt-nosudo/master/sign_csr.py ---2015-01-18 21:43:22-- https://raw.githubusercontent.com/diafygi/letsencrypt-nosudo/master/sign_csr.py -Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 199.27.79.133 -Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|199.27.79.133|:443... connected. -HTTP request sent, awaiting response... 200 OK -Length: 11057 (11K) [text/plain] -Saving to: ‘sign_csr.py’ - -100%[==================================================================>] 11,057 --.-K/s in 0.06s - -2015-01-18 21:43:22 (172 KB/s) - ‘sign_csr.py’ saved [11057/11057] - -user@hostname:~$ python sign_csr.py cert.csr > signed.crt +user@hostname:~$ openssl rsa -in user.key -pubout > user.pub +writing RSA key +user@hostname:~$ openssl genrsa 4096 > domain.key +Generating RSA private key, 4096 bit long modulus +.................................................................................................................................................................................++ +...........................................++ +e is 65537 (0x10001) +user@hostname:~$ openssl req -new -sha256 -key domain.key -subj "/CN=letsencrypt.daylightpirates.org" > domain.csr +user@hostname:~$ python sign_csr.py user.pub domain.csr > signed.crt +Reading pubkey file... +Found public key! Reading csr file... Found domain 'letsencrypt.daylightpirates.org' -Requesting challenges...Challenges received! -Parsing dvsni challenge... -Generating test configuation... -Generating test key for dvsni challenge... -Test key generated! - -==================================================== -================USER ACTION REQUIRED================ -==================================================== - -Since we don't ask for your private key or sudo access, you will need -to do some manual commands in order to get a signed certificate. Here's -what you need to do: - -1. Sign some files requested by the certificate authority. -2. Copy a test key and certificate to your server. -3. Run an https server with the test key and certificate. - -We've listed the commands you need to do this below. You should be able -to copy and paste them into a new terminal window. - -(NOTE: Replace 'priv.key' below with your private key, if different) -(NOTE: Replace 'ubuntu' below with your sudo user, if different) - -COMMANDS: --------------------------- -#Step 1: Sign the needed files -openssl dgst -sha256 -sign priv.key -out test_XhYOdY.msgsig test_vuK3N0.msg -openssl dgst -sha256 -sign priv.key -out test_Y5jK3k.dersig test_dQe_Zk.der - -#Step 2: Copy the test key and certificate to your server -scp test_j3Lumf.pem ubuntu@letsencrypt.daylightpirates.org:test_j3Lumf.pem -scp test_RDBEK7.crt ubuntu@letsencrypt.daylightpirates.org:test_RDBEK7.crt - -#Step 3: Run an https server with the test key and certificate -ssh -t ubuntu@letsencrypt.daylightpirates.org "sudo python -c \"import BaseHTTPServer, ssl; \ - httpd = BaseHTTPServer.HTTPServer(('0.0.0.0', 443), BaseHTTPServer.BaseHTTPRequestHandler); \ - httpd.socket = ssl.wrap_socket(httpd.socket, keyfile='test_j3Lumf.pem', certfile='test_RDBEK7.crt'); \ - httpd.serve_forever()\"" --------------------------- - -==================================================== -==================================================== -==================================================== + +STEP 1: You need to sign some files (replace 'user.key' with your account private key). + +openssl dgst -sha256 -sign user.key -out register_TeH8Cg.sig register_jzlzOk.json +openssl dgst -sha256 -sign user.key -out domain_FOtDWV.sig domain_dkaWo7.json +openssl dgst -sha256 -sign user.key -out challenge_IxfeES.sig challenge_svyiIw.json Press Enter when you've run the above commands in a new terminal window... -Sending challenge response... -Deferred... -Sending certificate request... -Exporting signed certificate... -Done! Your certificate is signed by the certificate authority! +Registering... +Requesting challenges... + +STEP 2: You need to run these two commands on letsencrypt.daylightpirates.org (don't stop the python command). + +openssl req -new -newkey rsa:2048 -days 365 -subj "/CN=a" -nodes -x509 -keyout a.key -out a.crt +sudo python -c "import BaseHTTPServer, ssl; \ + h = BaseHTTPServer.BaseHTTPRequestHandler; \ + h.do_GET = lambda r: r.send_response(200) or r.end_headers() or r.wfile.write('Zz7fkg1LAAxOomahwF5jP67ZJDFjQSkUDPAbLIMCtvY'); \ + s = BaseHTTPServer.HTTPServer(('0.0.0.0', 443), h); \ + s.socket = ssl.wrap_socket(s.socket, keyfile='a.key', certfile='a.crt'); \ + s.serve_forever()" + +Press Enter when you've got the python command running on your server... +Requesting verification... + +STEP 3: You need to sign one more file (replace 'user.key' with your account private key). + +openssl dgst -sha256 -sign user.key -out cert_97g7hU.sig cert_dDbKbs.json + +Press Enter when you've run the above command in a new terminal window... +Requesting signature... +Certificate signed! +You can stop running the python command on your server (Ctrl+C works). user@hostname:~$ cat signed.crt -----BEGIN CERTIFICATE----- -MIIEEjCCAvqgAwIBAgIENL8QdDANBgkqhkiG9w0BAQUFADAPMQ0wCwYDVQQKEwRB -Q01FMB4XDTE1MDExOTA0NDkxNFoXDTE2MDExOTA0NDkxNFowKjEoMCYGA1UEAxMf -bGV0c2VuY3J5cHQuZGF5bGlnaHRwaXJhdGVzLm9yZzCCAiIwDQYJKoZIhvcNAQEB -BQADggIPADCCAgoCggIBALDUa5ZczCKfYJQ6VZgUv0hELX2ZhU5DMYYlfGByu9KJ -myUEsU07Tcw/vsN8g8X1wYoCtm8j/H3aT0wxN5VcUXfgVPCZBp5uD0KzdZKgRiRR -Vwp0PKi1IQkrCi1ZBAQUlkCyVzsl0yjSkyf+c9aqljzPUf0/vK7HK/HJMds3wak7 -go/Z1FJD7ba8JAZStpnRvzTHfAW3vVnJ9cwoKloMl6eCs3+ICfXlA/mx0F5QG6EI -BYgOH2VyJ9ji584vM1dqc3eR2AdVuCPFCPf6O8EQ5UHx0zr15IdQ0GZIC11WTW+v -S0h7PUvbar9rJCHQAWIrvqxpHZKhCM/Nf3TIl9NTXtdJYQd4QlBJ+4WSCJCm3nx8 -UdeT8yQkYJSz0y0nSbtF05h+Ly/KvtJy4APblRF+IO2pZ2g9iCVk2e29hfYo7ps5 -mIy8eG3ibGWif1MeZN+lJfeDx5bu/kcjr/mUVrXHyxnPjG/nNxBDE/ff714NfHQ0 -TIPA2leR5LQQGtyLD3F6HPCpmgcJfS5sy/XfAFdixCBTDzvFUgnjFQiMOljSicL2 -VmF+3s+K/u61IafjqpivuPwzdO21l3gCOrKgdxlT6trNavhe000d2mIZrv/brXse -sClkTikGcREIfgwtDX3p1ckrMmkbyawgwLDLIPb0gNfBCWXpiAu+scY5ZkYOlg8J -AgMBAAGjWzBZMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgWgMBMGA1UdJQQMMAoGCCsG -AQUFBwMBMCoGA1UdEQQjMCGCH2xldHNlbmNyeXB0LmRheWxpZ2h0cGlyYXRlcy5v -cmcwDQYJKoZIhvcNAQEFBQADggEBAFNXALi2n6s7zcfz97da3rts1dd8OAJ62GMV -idT68mDx1u3CwgFBLYmhUfnUYY2AKL1vbWJ25s9eeFdJEbVzlllE6MvPcqZ/j3Iz -Nqvb/oAqGEXEBxir1d1t2M5TQgLFymOUBSDuPWzwNK0O9kGS4Di9vIlADKYgBSPQ -KxuZ0uDlVkhXKOYjPtcNJh7xlvBR90UC/l1r73L8GW2cyXdKvYy+E0Cg3NrZ3ptZ -LR/qXdhLTL8P5beEGZei8H8p4nX2e/TvIbXsSDnAQDWRmzRTTuJtS0/VGNaB4HOW -vU193yL7w7n/bMVCw5FO/1t/Ba1xMRxWjPkSaOAk7fVjOjo6M70= +MIIFPDCCBCagAwIBAgIQEwAAAAAAASFvBeWRs661qDALBgkqhkiG9w0BAQswHzEd +MBsGA1UEAwwUaGFwcHkgaGFja2VyIGZha2UgQ0EwHhcNMTUwNjExMTkxMDAwWhcN +MTYwNjEwMTkxMDAwWjAqMSgwJgYDVQQDEx9sZXRzZW5jcnlwdC5kYXlsaWdodHBp +cmF0ZXMub3JnMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAykwwRsfK +3U6BCBn6MhIvi5yp7wvM9p5dAjesWcek3aKmpDWolNhaXhwRpIuWrftpcL3co+1j +8Oq1c1cqOGK/9y4bLN1YedL4NBC3quF8b+aP5y9Wb0+IUmlKZfS8rzPqnprNx1tS +vabFKfiUq4uGaRGxbN9e7/Zz9tkpd1Dd2pL2AZx4eY91Mn06/f1LkzUQGndQC44R +12v7DgCuHFrrStT3qcms6DhvHu2s5BUXncgKIGak9tpiVQn5KK0wc3MDKfA5NOAt +BvoFKbIwCbPxqTCGYmNWXuKbQDC5iDnXFOES2jzCTY6ctuJMqVVDQjVVmBsdalj6 +2Qly42ZOZ74QwygW7uPYIGQNnog/U3OjFAzr4vTGDG8Vmx2Q3UC54E1uAFoU6vPv +tnC9lF7BXaJv/brA8j+QnJLHAOu42DGaqyhc43PZXYQ9LFKiSDOzIz99BTwISLtV +TlWpacpIfvJRxzWgAbzE1tUDe6o4yUWfqJ+l7pLzMb5KdFTA4o1LYeb3OA5DZSGF +chLcDzotneoyB3/oMxcx7Izgt8A+ukI+YS39FUIZtaQEUvsrQa4A0z038a9M+0lP +4CiGoqChiRmtIfg+AnK2jePCw0RMkgMinLlVW0BoSDkjKlqpaNystfPy4Xng50VB +anCHccfBz7iePL1ZYtRD2s6Ic26AbfPoI/sCAwEAAaOCAWswggFnMA4GA1UdDwEB +/wQEAwIAoDATBgNVHSUEDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMB0GA1Ud +DgQWBBQnrwlHgS8Q3KeHDrvFgFToJn6h7jAfBgNVHSMEGDAWgBT7eE8S+WAVgyyf +F380GbMuNupBiTBuBggrBgEFBQcBAQRiMGAwLgYIKwYBBQUHMAGGImh0dHA6Ly9p +bnQteDEubGV0c2VuY3J5cHQub3JnL29jc3AwLgYIKwYBBQUHMAKGImh0dHA6Ly9p +bnQteDEubGV0c2VuY3J5cHQub3JnL2NlcnQwKgYDVR0RBCMwIYIfbGV0c2VuY3J5 +cHQuZGF5bGlnaHRwaXJhdGVzLm9yZzAiBgNVHSAEGzAZMA0GCysGAQQBgt8TAQEB +MAgGBmeBDAECATAyBgNVHR8EKzApMCegJaAjhiFodHRwOi8vaW50LXgxLmxldHNl +bmNyeXB0Lm9yZy9jcmwwCwYJKoZIhvcNAQELA4IBAQBRvvFNlY1KkVmgGQvjRjDY +BlZ9nypDk3qRWfN/9PPZarShQr5tsfEFzB09AspBoOZO3hQDegjFllqBSeZ3T/No +SdgApizz0WnQT3PsgRZoObmr88RniRCY+2DOkMQCeuhRJt5f/nQCtPmQMwvO3G6V +Ruud8omn+coSoY1WGd5BYBaUoHznrfAuWFN7BwUW2yPa2z14iAMDfXh6RfWWS2dZ +TfS6UWrh6s631gS6ptbsAyD1n4eAtcg6dh1IlgqVG4oDGxTZYrx7uqB4Cwge+cOD +o/PkONqRzD++KGDfPHyjBdmAp99+MXD9EhxUQopQ884PaSYvcIhwcpFOxD9lzOun -----END CERTIFICATE----- -user@hostname:~$ +user@hostname:~$ ``` ###Manual Commands (the stuff the script asked you to do in a 2nd terminal) ``` -user@hostname:~$ #Step 1: Sign the needed files -user@hostname:~$ openssl dgst -sha256 -sign priv.key -out test_XhYOdY.msgsig test_vuK3N0.msg -user@hostname:~$ openssl dgst -sha256 -sign priv.key -out test_Y5jK3k.dersig test_dQe_Zk.der -user@hostname:~$ -user@hostname:~$ #Step 2: Copy the test key and certificate to your server -user@hostname:~$ scp test_j3Lumf.pem ubuntu@letsencrypt.daylightpirates.org:test_j3Lumf.pem -test_j3Lumf.pem 100% 3272 3.2KB/s 00:00 -user@hostname:~$ scp test_RDBEK7.crt ubuntu@letsencrypt.daylightpirates.org:test_RDBEK7.crt -test_RDBEK7.crt 100% 1996 2.0KB/s 00:00 -user@hostname:~$ -user@hostname:~$ #Step 3: Run an https server with the test key and certificate -user@hostname:~$ ssh -t ubuntu@letsencrypt.daylightpirates.org "sudo python -c \"import BaseHTTPServer, ssl; \ -> httpd = BaseHTTPServer.HTTPServer(('0.0.0.0', 443), BaseHTTPServer.BaseHTTPRequestHandler); \ -> httpd.socket = ssl.wrap_socket(httpd.socket, keyfile='test_j3Lumf.pem', certfile='test_RDBEK7.crt'); \ -> httpd.serve_forever()\"" - -######################################################## -## Wait until sign_csr.py is done before killing this ## -######################################################## +#first set of signed files +user@hostname:~$ openssl dgst -sha256 -sign user.key -out register_TeH8Cg.sig register_jzlzOk.json +user@hostname:~$ openssl dgst -sha256 -sign user.key -out domain_FOtDWV.sig domain_dkaWo7.json +user@hostname:~$ openssl dgst -sha256 -sign user.key -out challenge_IxfeES.sig challenge_svyiIw.json +user@hostname:~$ + +#second set of signed files +user@hostname:~$ openssl dgst -sha256 -sign user.key -out cert_97g7hU.sig cert_dDbKbs.json +user@hostname:~$ +``` +###Server Commands (the stuff the script asked you to do on your server) +``` +ubuntu@letsencrypt.daylightpirates.org:~$ openssl req -new -newkey rsa:2048 -days 365 -subj "/CN=a" -nodes -x509 -keyout a.key -out a.crt +Generating a 2048 bit RSA private key +........................+++ +.....+++ +writing new private key to 'a.key' +----- +ubuntu@letsencrypt.daylightpirates.org:~$ sudo python -c "import BaseHTTPServer, ssl; \ +> h = BaseHTTPServer.BaseHTTPRequestHandler; \ +> h.do_GET = lambda r: r.send_response(200) or r.end_headers() or r.wfile.write('Zz7fkg1LAAxOomahwF5jP67ZJDFjQSkUDPAbLIMCtvY'); \ +> s = BaseHTTPServer.HTTPServer(('0.0.0.0', 443), h); \ +> s.socket = ssl.wrap_socket(s.socket, keyfile='a.key', certfile='a.crt'); \ +> s.serve_forever()" +54.183.196.250 - - [11/Jun/2015 16:07:45] "GET /.well-known/acme-challenge/Abc46LNljZ5zjen6f-mcCA HTTP/1.1" 200 - ^CTraceback (most recent call last): File "<string>", line 1, in <module> File "/usr/lib/python2.7/SocketServer.py", line 236, in serve_forever @@ -273,11 +252,9 @@ user@hostname:~$ ssh -t ubuntu@letsencrypt.daylightpirates.org "sudo python -c \ File "/usr/lib/python2.7/SocketServer.py", line 155, in _eintr_retry return func(*args) KeyboardInterrupt -Connection to letsencrypt.daylightpirates.org closed. -user@hostname:~$ +ubuntu@letsencrypt.daylightpirates.org:~$ ``` - ##How to use the signed https certificate The signed https certificate that is output by this script can be used along @@ -292,7 +269,7 @@ server { server_name letsencrypt.daylightpirates.org; ssl on; ssl_certificate signed.crt; - ssl_certificate_key priv.key; + ssl_certificate_key domain.key; ssl_session_timeout 5m; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers EECDH+aRSA+AES256:EDH+aRSA+AES256:EECDH+aRSA+AES128:EDH+aRSA+AES128; @@ -319,7 +296,7 @@ better. The script itself, `sign_csr.py`, is less than 300 lines of code, so feel free to read through it! I tried to comment things well and make it crystal clear what it's doing. -For example, it currently can't do any ACME challenges besides dvsni. Maybe +For example, it currently can't do any ACME challenges besides SimpleHTTPS. Maybe someone could do a pull request to add more challenge compatibility? Also, it currently can't revoke certificates, and I don't want to include that in the `sign_csr.py` script. Perhaps there should also be a `revoke_crt.py` script? |