README.md in acme-client-0.1.3 vs README.md in acme-client-0.2.0

- old
+ new

@@ -1,6 +1,7 @@ # Acme::Client +[![Build Status](https://travis-ci.org/unixcharles/acme-client.svg?branch=master)](https://travis-ci.org/unixcharles/acme-client) `acme-client` is a client implementation of the [ACME](https://letsencrypt.github.io/acme-spec) protocol in Ruby. You can find the server reference implementation for ACME server [here](https://github.com/letsencrypt/boulder) and also the a reference [client](https://github.com/letsencrypt/letsencrypt) in python. @@ -8,16 +9,18 @@ ## Usage ```ruby # We're going to need a private key. +require 'openssl' private_key = OpenSSL::PKey::RSA.new(2048) # We need an ACME server to talk to, see github.com/letsencrypt/boulder endpoint = 'https://acme-staging.api.letsencrypt.org' # Initialize the client +require 'acme-client' client = Acme::Client.new(private_key: private_key, endpoint: endpoint) # If the private key is not known to the server, we need to register it for the first time. registration = client.register(contact: 'mailto:unixcharles@gmail.com') @@ -27,54 +30,78 @@ # Let's try to optain a certificate for yourdomain.com # We need to prove that we control the domain using one of the challenges method. authorization = client.authorize(domain: 'yourdomain.com') -# For now the only challenge method supprted by the client is simple_http. -simple_http = authorization.simple_http +# For now the only challenge method supprted by the client is http-01. +challenge = authorization.http01 -# The SimpleHTTP method will require you to response to an HTTP request. +# The http-01 method will require you to response to an HTTP request. # You can retrieve the expected path for the file. -simple_http.filename # => ".well-known/acme-challenge/:some_token" +challenge.filename # => ".well-known/acme-challenge/:some_token" # You can generate the body of the expected response. -simple_http.file_content # => 'string of JWS signed json' +challenge.file_content # => 'string token and JWK thumbprint' -# You can send no Content-Type at all but if you send one it has to be 'application/jose+json'. -simple_http.content_type +# You can send no Content-Type at all but if you send one it has to be 'text/plain'. +challenge.content_type +# Save the file. We'll create a public directory to serve it from, and we'll creating the challenge directory. +FileUtils.mkdir_p( File.join( 'public', File.dirname( challenge.filename ) ) ) + +# Then writing the file +File.write( File.join( 'public', challenge.filename), challenge.file_content ) + +# The challenge file can be server with a Ruby webserver such as run a webserver in another console. You may need to forward ports on your router +#ruby -run -e httpd public -p 8080 --bind-address 0.0.0.0 + + # Once you are ready to serve the confirmation request you can proceed. -simple_http.request_verification # => true -simple_http.verify_status # => 'pending' +challenge.request_verification # => true +challenge.verify_status # => 'pending' # Wait a bit for the server to make the request, or really just blink, it should be fast. sleep(1) -simple_http.verify_status # => 'valid' +challenge.verify_status # => 'valid' # We're going to need a CSR, lets do this real quick with Ruby+OpenSSL. csr = OpenSSL::X509::Request.new # We need a private key for the certificate, not the same as the account key. certificate_private_key = OpenSSL::PKey::RSA.new(2048) # We just going to add the domain but normally you might want to provide more information. csr.subject = OpenSSL::X509::Name.new([ - ['CN', common_name, OpenSSL::ASN1::UTF8STRING] + ['CN', 'yourdomain.com', OpenSSL::ASN1::UTF8STRING] ]) csr.public_key = certificate_private_key.public_key csr.sign(certificate_private_key, OpenSSL::Digest::SHA256.new) # We can now request a certificate -client.new_certificate(csr) # => #<OpenSSL::X509::Certificate ....> +certificate = client.new_certificate(csr) # => #<Acme::Certificate ....> + +# Save the certificate and key +File.write("cert.pem", certificate.to_pem) +File.write("key.pem", certificate_private_key.to_pem) +File.write("chain.pem", certificate.chain_to_pem) +File.write("fullchain.pem", certificate.fullchain_to_pem) + +# Start a webserver, using your shiny new certificate +# ruby -r openssl -r webrick -r 'webrick/https' -e "s = WEBrick::HTTPServer.new( +# :Port => 8443, +# :DocumentRoot => Dir.pwd, +# :SSLEnable => true, +# :SSLPrivateKey => OpenSSL::PKey::RSA.new( File.read('key.pem') ), +# :SSLCertificate => OpenSSL::X509::Certificate.new( File.read('cert.pem') )); trap('INT') { s.shutdown }; s.start" ``` # Not implemented - Recovery methods are not implemented. -- SimpleHTTP is the only challenge method implemented +- http-01 is the only challenge method implemented ## Development All the tests use VCR to mock the interaction with the server but if you need to record new interation against the server simply clone boulder and