hunchentoot define-easy-handler with ssl? - ssl

I use define-easy-handler all the time. I now have a freshly minted ssl certificate and associated pem files, but can't figure out what the ssl equivalent of d-e-h is.
For example, I have:
(hunchentoot:define-easy-handler
(login :uri "/login")
()
(login-html))
which is just a simple form whose formaction goes here:
(hunchentoot:define-easy-handler
(dologin :uri "/dologin")
(email password)
(dologin-html email password))
I got the required .pem files from freecert, so I think that I have the files that go to :SSL-CERTIFICATE-FILE and :SSL-PRIVATEKEY-FILE. I've tried various args to the above to make this work, but can't seem to get it to work. Can someone give me an example of how to do this?
Thanks in advance for you help!

You can keep your easy-handlers and change the type of acceptor you need.
(defpackage :web (:use :cl :hunchentoot))
(in-package :web)
;; This url can be accessed by all acceptors
(define-easy-handler (no-ssl :uri "/normal") ()
(setf (content-type*) "text/plain")
"NORMAL PAGE")
;; This url can be accessed only by an acceptor named SSL
(define-easy-handler (ssl :uri "/secure" :acceptor-names '(ssl)) ()
(setf (content-type*) "text/plain")
"SECURED PAGE")
For tests, if you don't already have a self-signed certificate , you can do:
$ cd /tmp
$ openssl req -new -x509 -nodes -out server.crt -keyout server.key
Then, we define two kinds of acceptors:
(defvar *no-ssl-acceptor*
(make-instance 'easy-acceptor :port 8080))
(defvar *ssl-acceptor*
(make-instance 'easy-ssl-acceptor
:name 'ssl
:port 7777
:ssl-privatekey-file #P"/tmp/server.key"
:ssl-certificate-file #P"/tmp/server.crt"))
Start them:
(start *ssl-acceptor*)
(start *no-ssl-acceptor*)
Your browser should complain the first time you try to access HTTPS pages (ignore the security exception).
http://localhost:8080/normal
http://localhost:8080/secure (should fail with 404)
https://localhost:7777/normal
https://localhost:7777/secure
Note also that the :acceptor-names argument is optional (thanks #Simeon Ikudabo), here above it was added explictly for the examples. You can just define an SSL acceptor and let all your pages be served over a secure link.

This is not a function of the handlers but of the acceptor. All you need to do is use an easy-ssl-acceptor instead of an easy-acceptor for starting your server:
(hunchentoot:start (make-instance 'hunchentoot:easy-ssl-acceptor :port 4242))

Related

Getting human readable public certificate using dig command

I'm trying to read public cert using dig command as:
dig <domain> -t CERT
which will come back as something like:
;; ANSWER SECTION:
domain. 3600 IN CERT PKIX 54727 RSASHA1 MIIFfTCCBGWgAwIBAgIQCTinFRnGvxrlJ4zqeWKf/TANBgkqhkiG9w0B AQsFADB/MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEg MB4GA1UEChMXTmV4dGdlbiBIZWFsdGhjYXJlIEluYy4xOTA3BgNVBAMT ME5leHRnZW4gSGVhbHRoY2FyZSBEaXJlY3QgU2VjdXJlIE1lc3NhZ2lu ZyBDQSBHMjAeFw0yMjAzMDEwMDAwMDBaFw0yNDAyMjkyMzU5NTlaMGkx CzAJBgNVBAYTAlVTMREwDwYDVQQIEwhOZXcgWW9yazERMA8GA1UEBxMI TmV3IFlvcmsxFjAUBgNVBAoTDUhlYWx0aGl4LCBJbmMxHDAaBgNVBAMT E2RpcmVjdC5oZWFsdGhpeC5vcmcwggEiMA0GCSqGSIb3DQEBAQUAA4IB DwAwggEKAoIBAQCj0VULvmE0VY0yU27696Lo1PGXk4bzPjwQANn0xtTp i13zc0fgWSHDMaDBuF6lRjw9uzIhXXxsakYVPhQjm1BrpBfnRLWbrm9c XHpvlumbSc/oGGZf/k7UotaAQwwUmbvBxaq4lyIID7qZMLZ6HssbNeys jEvHRfBXIs1lohEZgwQdrM/MnNLF63rqY7Ymh2qJUhHuu4qGKJO8RiVf gH4Qly8zAaBMlQ/XevvKPdPPtGyf923Hk7LABHta6WtaPCEgazYBjVmq SKL5mYaNHXYNjMRFe4dRH7e7hYaLmcWNdcMXFvOttYNCYM1YsFqAGOAL iGA5mm/dsomiDB9atdXHAgMBAAGjggIJMIICBTAfBgNVHSMEGDAWgBRW JSd4pIqHpJ781l5+fKpIP7aOOzAdBgNVHQ4EFgQU7aKfWKxg3rF+/eta 788DoC6i+r4wHgYDVR0RBBcwFYITZGlyZWN0LmhlYWx0aGl4Lm9yZzAO BgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwQwgakGA1Ud HwSBoTCBnjBNoEugSYZHaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL05l eHRnZW5IZWFsdGhjYXJlRGlyZWN0U2VjdXJlTWVzc2FnaW5nQ0FHMi5j cmwwTaBLoEmGR2h0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9OZXh0Z2Vu SGVhbHRoY2FyZURpcmVjdFNlY3VyZU1lc3NhZ2luZ0NBRzIuY3JsMDQG A1UdIAQtMCswDQYLKwYBBAGCwVsAAgAwDAYKKwYBBAGCwVsBAzAMBgor BgEEAYLBWwIBMIGNBggrBgEFBQcBAQSBgDB+MCQGCCsGAQUFBzABhhho dHRwOi8vb2NzcC5kaWdpY2VydC5jb20wVgYIKwYBBQUHMAKGSmh0dHA6 Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9OZXh0Z2VuSGVhbHRoY2FyZURp cmVjdFNlY3VyZU1lc3NhZ2luZ0NBRzIuY3J0MAwGA1UdEwEB/wQCMAAw DQYJKoZIhvcNAQELBQADggEBADXqYelrcmLRV0olDpe1IpBfDoR5bxYy nvGmkrI/a2Wa1ZqbaVPsR3KevaDwKk/osXNIdcc1MbTsA6m1Lc0otJZd IlSn3YjzYZHwJqwzeL4OxYwJs8Dytdlxa3c6UYRtKNeT0FU8cKtQoXo2 3N9WG21UwoUwIfU0k86tX5saTqeUYgy2q4FWFIdjzCnL6+MKsEtpzKay AM6p96SUKLfBaUYMaHeFgQbkR9g/kcgQY89HtckzuOZwtYdEfuOlY/0Y dnzX+mmCA3FvKNj06oChiRNJeBOD3gbkFWTm0SJqRz61ciSssqvFTB/M vY2EVuDKUikwgfjlJnic7cj60TJrBFE=
My question is how can I get that cert in a PEM format so then can transfer it to the human readable like an ouput from openssl X509 to text.

Problem getting complete .pem from ansible letsencrypt / acme_certificate module

I was using Ansible 2.4 and included the letsencrypt module in one of my roles hoping to get a complete `.pem' format file at the end (key, chain, cert). There was no problem generating the key or using the csr to request the new cert, and no problem with the challenge, but when everything was done, I was only getting the certificate back, no chain.
When I tried to use them, Apache would fail to start saying that the key and the cert did not match. I assumed that this was because I didn't include the chain which was missing.
According to the docs here: https://docs.ansible.com/ansible/latest/modules/acme_certificate_module.html the chain|chain_dest and fullchain|fullchain_dest parameters weren't added until Ansible 2.5. So I upgraded to Ansible 2.7 (via git), and I'm still running into the exact same error...
FAILED! => {
"changed": false,
"msg": "
Unsupported parameters for (letsencrypt) module: chain_dest, fullchain_dest
Supported parameters include: account_email, account_key, acme_directory, agreement,
challenge, csr, data, dest, remaining_days"
}
I've tried the aliases and current names for both but nothing is working. Here is my current challenge-response call:
- name: Let the challenge be validated and retrieve the cert and intermediate certificate
letsencrypt:
account_key: /etc/ssl/lets_encrypt.key
account_email: ###########.###
csr: /etc/ssl/{{ myhost.public_hostname }}.csr
dest: /etc/ssl/{{ myhost.public_hostname }}.crt
chain_dest: /etc/ssl/{{ myhost.public_hostname }}.int
fullchain_dest: /etc/ssl/{{ myhost.public_hostname }}.pem
challenge: dns-01
acme_directory: https://acme-v01.api.letsencrypt.org/directory
remaining_days: 60
data: "{{ le_com_challenge }}"
tags: sslcert
The documentation says that this is valid, but the error response does not include chain|chain_dest or fullchain|fullchain_dest as valid parameters.
I would, from the docs, expect that this response should result in the new certificate being created (.crt), the chain being created (.int), and the fullchain to be created (.pem).
Any help would be appreciated.
Should have waited 5 minutes... seems that the newer parameters are only available under the newer module name acme_certificate, even though it says letsencrypt was a valid alias. As soon as I updated this it worked.

Local HTTPS server with SNI

There is a ton of information available about cURL and SSL, but not so much is out there about writing a server. I have a small local server written in PHP that I would like to have TLS/SSL enabled. I am having issues with my server crashing upon secure connections. I am only receiving the error, "PHP Warning: stream_socket_accept(): Failed to enable crypto". I have an identical server running without TLS, and it is working fine. I have an idea it is the certificates, or the connection to/reading the certificates. However, I am not sure if it is an error on how I generated the certificates, how I have them joined to PEM, or something else. Also, for our domains, I've used *.domain.tld in both the code below, as well as the local name in the cert creation.
Furthermore, the certificates shown in the web browser show the 127.0.0.1 cert and not the localhost (or other domains) certificates regardless of the domain requested. Is that because the 127.0.0.1 is set as the local cert? About the certificates- this is my current code for creating the .pem file to use on the server:
sudo openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout apache.key -out apache.crt
apache.crt apache.key > joined.pem
A basic rendition of the server code is:
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
$flags = STREAM_SERVER_BIND|STREAM_SERVER_LISTEN;
$ctx = stream_context_create(['ssl' => [
'local_cert' => "{path}/Websites/127.0.0.1/certs/joined.pem",
'SNI_server_certs' => [
"127.0.0.1" => "{path}/Websites/127.0.0.1/certs/joined.pem",
"localhost" => "{path}//Websites/localhost/certs/joined.pem",
]
]]);
stream_context_set_option($ctx, 'ssl', 'ssl_method', 'STREAM_CRYPTO_METHOD_TLSv23_SERVER');
stream_context_set_option($ctx, 'ssl', 'allow_self_signed', true);
stream_context_set_option($ctx, 'ssl', 'verify_peer', false);
stream_context_set_option($ctx, 'ssl', 'ciphers', "HIGH");
$socket = stream_socket_server("tls://127.0.0.1:8443", $errno, $errstr, $flags, $ctx);
while ( $client = stream_socket_accept($socket, "-1", $clientIP)):
$msg = fread($client, 8192);
$resp = "HTTP/1.1 200 OK\r\nContent-type: text/html\r\n\r\n<h1>Hi, you are secured.<br>{$msg}";
fwrite($client,$resp );
fclose($client);
endwhile;
One more thing, what is the proper cipher to set for appeasing all of the major browsers out there, Chrome seems to play by its own rules.
Any ideas what I am missing here?
My issue was not setting SANs during the certificate creation. The link https://serverfault.com/questions/880804/can-not-get-rid-of-neterr-cert-common-name-invalid-error-in-chrome-with-self corrected my issues.

Alamofire and PEM certificate

I have a .pem file which will successfully connect to my website via the --cert parameter of curl. I then converted that to a der file:
openssl x509 -inform PEM -outform DER -in client.pem -out cert.der
Then I loaded that cert.der into my project and I'm now trying to use that with Alamofire, following the example on their homepage:
let serverTrustPolicy = ServerTrustPolicy.PinCertificates(
certificates: ServerTrustPolicy.certificatesInBundle(),
validateCertificateChain: true,
validateHost: true
)
let policyManager = ServerTrustPolicyManager(policies: ["my.domain.com" : serverTrustPolicy])
manager = Alamofire.Manager(configuration: configuration, serverTrustPolicyManager: policyManager)
manager.request(.GET, url, parameters: params, encoding: .URLEncodedInURL, headers: nil)
.authenticate(usingCredential: credential)
.validate()
.responseJSON {
When that runs though it just fails and I get a 'cancelled' as the error's localizedDescription, which is what Alamofire does when authentication fails.
What am I doing wrong?
The Alamofire cert pinning logic does not currently support this use case. It is only designed to handle cert and public key pinning, not client certificates used to authenticate with the server. This is something we could support in the future if this is a common use case.
With that said, I'm assuming in this case you are receiving a NSURLAuthenticationChallenge with a protection space that has an authentication method of type .NSURLAuthenticationMethodClientCertificate. In these cases, you need to evaluate the host of the challenge, then create an NSURLCredential using the credentialWithIdentity:certificates:persistence: API. By passing this credential off to the completion handler, the client certificate should be sent to the server to authenticate the connection. More info can be found here.
Client certificate authentication (NSURLAuthenticationMethodClientCertificate) requires the system identity and all certificates needed to authenticate with the server. Create an NSURLCredential object with credentialWithIdentity:certificates:persistence:.
I've never actually had a need to use this type of authentication before. You'll need to override the auth challenge SessionDelegate closure using the task override closure to get this working.

Clojure SSL specify local cert to use as a client side certificate

This comes from the python documentation for Python "Requests" http library
"You can also specify a local cert to use as client side certificate, as a single file (containing the private key and the certificate) or as a tuple of both file’s path":
>>> requests.get('https://kennethreitz.com', cert=('/path/server.crt', '/path/key'))
<Response [200]>
http://docs.python-requests.org/en/latest/user/advanced/
What's a good way to do the same thing in Clojure ? I looked at clj-http and http-kit but did not see an example
Have you seen async-http-client?
It has specific tests for cert handling you can view here. The API docs are here, particularly relevant would be the namespace http.async.client.cert.
From that test, a typical example of loading keystore and certificate is:
(def ks-file "test-resources/keystore.jks")
(def cert-file "test-resources/certificate.crt")
(def password "secret")
(defn load-test-certificate [] (load-x509-cert cert-file))
(defn load-test-keystore [] (load-keystore (resource-stream ks-file) password))