I'm checking ALPN support on NGINX with latest libressl 2.5.3. I think I have all correctly setup, but when I try to test from:
https://tools.keycdn.com/http2-test
Tell me : Yeah! DOMAIN supports HTTP/2.0
"ALPN is not supported"
Instead when I try to test locally with opnessl we can see alpn is correct with version h2
#openssl s_client -alpn h2 -connect domain:port | grep ALPN
depth=2 O = Digital Signature Trust Co., CN = DST Root CA X3
verify return:1
depth=1 C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
verify return:1
depth=0 CN = fbrqx.com
verify return:1
ALPN protocol: h2
What I'm doing wrong ?
Are correct the information provided by keycdn ?
Thanks.
Ricardo / Brqx.
Today keycdn works and tell us ALPN is supported.
Here we can see libressl information ( so with 2.5.3 version [April 2017] you can test openssl ):
openssl version -a
LibreSSL 2.5.3
built on: date not available
platform: information not available
options: bn(64,64) rc4(16x,int) des(idx,cisc,16,int) idea(int) blowfish(idx)
compiler: information not available
OPENSSLDIR: "/PATH/libressl/libressl-2.5.3/.openssl/etc/ssl"
How to test server :
1.From server ( with openssl client )
openssl s_client -alpn h2 -connect DOMAIN:PORT -status
New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES128-GCM-SHA256
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
ALPN protocol: h2
SSL-Session:
Protocol : TLSv1.2
Cipher : ECDHE-RSA-AES128-GCM-SHA256
Session-ID: 1FB23766E93F4983F3218F3E1C0058947DD60BEEB414CA50BDDF9009299A273B
Session-ID-ctx:
Master-Key: BBCC316C78C85C90066F660A5C1018F5F71CEADFF13AC406758BA06B0D07A5FFCF21395657CFF1B42760C371EE70281D
TLS session ticket lifetime hint: 300 (seconds)
TLS session ticket:
0000 - 06 48 61 b7 a7 63 23 ad-6a cf f9 47 39 49 c0 1a .Ha..c#.j..G9I..
0010 - b3 04 db ea 02 2e 46 a9-9a 6b 02 de b5 e9 bb c4 ......F..k......
0020 - 68 71 ba b2 62 27 08 76-f0 cb cb e6 e5 7d 4a 50 hq..b'.v.....}JP
0030 - f8 4d 40 24 2a 35 2a 7e-03 5b bc 27 73 7d 1a 14 .M#$*5*~.[.'s}..
0040 - f3 86 9d d9 33 42 49 c7-93 28 a0 f9 e3 4a cb 93 ....3BI..(...J..
0050 - 4d e7 43 bf 8d 8b 9d 3b-06 47 04 77 ca ca 0b 56 M.C....;.G.w...V
0060 - fc 6c ff 0d ac 69 7c b3-bb 6f fb 35 d5 75 7d aa .l...i|..o.5.u}.
0070 - d3 34 e1 04 f9 85 06 50-a2 3d 12 8d 69 39 53 32 .4.....P.=..i9S2
0080 - c7 c4 f3 84 93 fb 87 8c-48 a2 7b 8f 35 5a c0 4f ........H.{.5Z.O
0090 - 3c 58 39 3d 5d cf b1 10-b4 fa 19 9d 43 f2 09 c7 <X9=].......C...
Start Time: 1493112423
Timeout : 7200 (sec)
Verify return code: 0 (ok)
From client - Browser Google Chrome ( will tell us current connections what listen http2)
chrome://net-internals/#http2
This is the configuration on nginx :
server {
index index.html index.htm index.php;
# Direct http2
listen IP:PORT ssl http2;
# Haproxy redirection
listen IP:PORT http2 proxy_protocol;
...
And this one is the configuration on haproxy ( My idea is to use SSL layer between HA and Nginx so could be in different servers around the world).
frontend ABC
mode tcp
# Works with http11
# bind 0.0.0.0:PORT ssl crt /etc/haproxy/certs/DOMAIN.pem alpn http/1.1
# Works with http2 and http11
bind 0.0.0.0:PORT ssl crt /etc/haproxy/certs/DOMAIN.pem alpn h2,http/1.1 ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA
reqadd X-Forwarded-Proto:\ https
use_backend proxy_nginx if { ssl_fc_alpn -i h2 }
default_backend nginx
backend nginx
mode tcp
server server_nginx IP:PORT check ssl verify none
backend proxy_nginx
mode tcp
server proxy_nginx IP:PORT check send-proxy
...
Now everybody could have working Haproxy, Nginx with libressl 2.5.3 using http2 and alpn.
Interesting URLs to check :
https://gist.github.com/thisismitch/7c91e9b2b63f837a0c4b
https://www.mare-system.de/blog/page/1405201517/
https://jve.linuxwall.info/blog/index.php?post/2015/10/04/SHA1/SHA256-certificate-switching-with-HAProxy
https://wiki.mozilla.org/Security/Server_Side_TLS#Recommended_configurations
Best regards.
Ricardo / Brqx.
Related
I am trying to build a TCP checking on my backend servers using HAProxy version 1.5.8.
The behavior should be as follows:
Send binary data to server
Receive ACK as first packet
Receive confirmation data in second packet
So I need to check that after sending binary data I received ACK and after that other binary data in a second packet in a row.
Is it possible to do it with HAProxy.
I am trying to find it in documentation and also trying to create different configurations, unsuccessfully:
option tcp-check
tcp-check connect
tcp-check send-binary 303030303030
tcp-check expect binary 303030303030
Every time I received back from server ACK, connection is terminated by HAProxy with the result that the backend server is down.
EDIT:
I will receive the following:
First packet after sending data
0000 a0 66 10 09 2e 46 9c af ca bb aa 47 08 00 45 00 f...F.¯Ê»ªG..E.
0010 00 28 40 58 40 00 3e 06 d7 04 0a 1e 0b 34 0a 02 .(#X#.>.×....4..
0020 06 20 25 1c d5 80 91 0a f8 87 db 03 25 8f 50 10 . %.Õ...ø.Û.%.P.
0030 01 c9 03 d6 00 00 00 00 00 00 00 00 .É.Ö........
Second packet right after the above
0000 a0 66 10 09 2e 46 9c af ca bb aa 47 08 00 45 00 f...F.¯Ê»ªG..E.
0010 00 39 40 59 40 00 3e 06 d6 f2 0a 1e 0b 34 0a 02 .9#Y#.>.Öò...4..
0020 06 20 25 1c d5 80 91 0a f8 87 db 03 25 8f 50 18 . %.Õ...ø.Û.%.P.
0030 01 c9 2d 2e 00 00 00 0f 30 30 30 30 30 30 42 33 .É-.....000000B3
0040 30 30 43 48 45 43 4b 00CHECK
The first is without any data and I need to check that the second contains 000000.
EDIT2:
PCAP provided:
Normal behavior when communication goes directly from client to server, without HAProxy:
Normal behavior - client to server
Using HAProxy as load balancer, connecting to the same server and checking with the same command, failing to check:
failing check - HAProxy to server
backend configuration:
backend nodes
mode tcp
balance roundrobin
default-server inter 10s fall 3 rise 2
option tcp-check
tcp-check connect
tcp-check send-binary 303030303030423230303035434845434b
tcp-check expect binary 000f30303030303042333030434845434b
server server1 10.30.11.52:9500 check
server server2 10.30.11.52:9501 check
server server3 10.30.11.52:9502 check
Receive ACK as first packet
HA proxy does not work at the raw packet level but at the TCP level. At this level there is no such thing as an ACK as a single packet. There is not even the concept of a packet at this level. Instead there is only the concept of a data stream consisting of the received bytes.
Every time I received back from server ACK, connection is terminated by HAProxy with the result that the backend server is down.
Given that HA proxy does not care about packets with zero payload in the first place it is likely that your "ACK as first packet" is actually some packet which contains an ACK (as almost all TCP packets do) but also contains some payload, but not the one you expect with the "next packet". Since the payload does not match the payload you specify as expected the check fails.
Note that this is only an assumption made based on incomplete information about your "ACK as first packet". To prove the assumption one would actually need to see what is really going on on the wire, for example by having a packet capture.
EDIT#1: after the OP provided a some (undocumented) dump of the packets and some figuring out where the actual IP header in these packets starts (offset 14, i.e. prefixed with layer 2 ethernet header) it is clear that the first packet has no payload which means it gets completely ignored by the check. The second packet then has the following payload of 17 bytes:
0030 00 0f 30 30 30 30 30 30 42 33 ..000000B3
0040 30 30 43 48 45 43 4b 00CHECK
Given that the OP checks for binary 303030303030 but the actual payload is 00 0f 30 30 30 30 30 30 .... the given tcp-check expect ... does not match the actual payload and thus the check fails.
EDIT#2:
After the OP has provided the pcap of a connection without and with haproxy a difference in the behavior of both client/haproxy and server can be seen:
without haproxy:
client sends 2 bytes \x00\x11 to the server followed by 17 bytes \x30\x30....
server replies immediately with 17 bytes \x00\x0f\x30\x30....
with haproxy:
haproxy send 17 bytes \x30\x30... to the server. It does not send the initial 2 bytes \x00\x11 as done by the original server !!!
Server does not reply (except an ACK with no payload). After 6 seconds of inactivity haproxy closes the connection to the server and likely considers the check failed.
In summary: I think the haproxy check fails to send the proper request to the server, i.e. the first 2 bytes are missing. That's why the server will not respond at all and the check will fail after some timeout.
I am trying to deploy on my nginx instance a SSL certificate signed by own Intermediate CA, itself signed by own Root CA.
I have followed very carefully this very good OpenSSL guide to create my 3 certificates: the Root CA, the Intermediate CA and my leaf certificate.
When I connect with openssl to my running nginx instance I get:
$ openssl s_client -connect localhost:443
CONNECTED(00000003)
depth=2 C = FR, ST = France, L = Paris, O = Maugeri & Co, OU = Maugeri & Co Certificate Authority, CN = Maugeri & Co Root CA
verify error:num=19:self signed certificate in certificate chain
verify return:0
---
Certificate chain
0 s:/C=FR/ST=France/L=Paris/O=Maugeri & Co/OU=Maugeri & Co Web Services/CN=www.example.com
i:/C=FR/ST=France/O=Maugeri & Co/OU=Maugeri & Co Certificate Authority/CN=Maugeri & Co Intermediate CA
1 s:/C=FR/ST=France/O=Maugeri & Co/OU=Maugeri & Co Certificate Authority/CN=Maugeri & Co Intermediate CA
i:/C=FR/ST=France/L=Paris/O=Maugeri & Co/OU=Maugeri & Co Certificate Authority/CN=Maugeri & Co Root CA
2 s:/C=FR/ST=France/L=Paris/O=Maugeri & Co/OU=Maugeri & Co Certificate Authority/CN=Maugeri & Co Root CA
i:/C=FR/ST=France/L=Paris/O=Maugeri & Co/OU=Maugeri & Co Certificate Authority/CN=Maugeri & Co Root CA
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIF6TCCA9GgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwgYkxCzAJBgNVBAYTAkZS
MQ8wDQYDVQQIDAZGcmFuY2UxFTATBgNVBAoMDE1hdWdlcmkgJiBDbzErMCkGA1UE
CwwiTWF1Z2VyaSAmIENvIENlcnRpZmljYXRlIEF1dGhvcml0eTElMCMGA1UEAwwc
TWF1Z2VyaSAmIENvIEludGVybWVkaWF0ZSBDQTAeFw0xNzA4MjYwNzI1MzRaFw0x
ODA5MDUwNzI1MzRaMIGDMQswCQYDVQQGEwJGUjEPMA0GA1UECAwGRnJhbmNlMQ4w
DAYDVQQHDAVQYXJpczEVMBMGA1UECgwMTWF1Z2VyaSAmIENvMSIwIAYDVQQLDBlN
YXVnZXJpICYgQ28gV2ViIFNlcnZpY2VzMRgwFgYDVQQDDA93d3cuZXhhbXBsZS5j
b20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDITYGnv3hMemKsDwBi
Qr84aFEYURCLHlEDPQ0aF2zn0VdUt5a34Qj4ywTdICW7FFXUbUQPoz0XLtr0OXDu
B7n0uVzU16VIBNper6PBem8Rbyd0lw+z055mVRPDN7ac07STJ6tZsjKIBidQCc7e
weiBXGER30vqWLih7ez1vw7xrYl5iYxAmYKnQsXQNTpaYsSrxPmqQ+tB+uzvCTP4
emr8SyvIpSVqVajdxxBomx5b3m+NiEIiw3IOz9iicwxYeSEU9wgUd21C+lk3x7SV
8jGn5hyFrlFzVbj7M9qA5eyQMMH/KFUaSWW9qnoUUEf0JrMchmfe9Pl/JCBqMBTj
xDxhAgMBAAGjggFdMIIBWTAJBgNVHRMEAjAAMBEGCWCGSAGG+EIBAQQEAwIGQDAz
BglghkgBhvhCAQ0EJhYkT3BlblNTTCBHZW5lcmF0ZWQgU2VydmVyIENlcnRpZmlj
YXRlMB0GA1UdDgQWBBSW5SGY1Hwx3tpH/ZOp0sjR2iSJnDCBvwYDVR0jBIG3MIG0
gBTRAfURf9Lsyf0XyMoQGvhtk6zKiqGBl6SBlDCBkTELMAkGA1UEBhMCRlIxDzAN
BgNVBAgMBkZyYW5jZTEOMAwGA1UEBwwFUGFyaXMxFTATBgNVBAoMDE1hdWdlcmkg
JiBDbzErMCkGA1UECwwiTWF1Z2VyaSAmIENvIENlcnRpZmljYXRlIEF1dGhvcml0
eTEdMBsGA1UEAwwUTWF1Z2VyaSAmIENvIFJvb3QgQ0GCAhAAMA4GA1UdDwEB/wQE
AwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATANBgkqhkiG9w0BAQsFAAOCAgEApHGF
P/kOxKBjjFs8MG+lxVKK4j2EtJteqQ1Phve9aet0ZLuQvon59dHdc2pcSqX/SGex
CD5iR77E1nifGjsC1pp/7NL65lucpCYY00gCIIXO//BUBV6B6XjeKMdcRgVW2bUJ
kaLMwXMEdOkL2fwoFZtFI4YhzcdOk1gBrlvHslXj4swjrjLST87m6AOweCS5ldSq
/DZ7L4UiCqIGY8frVMXra7Q5I9xrwTRavnhbvp5WyC3IUCqOZ1U2hq6e6EeA3xf6
g6XgU7vf6V8xRYvjaTnUaKoE7cP92tgjfceyJFWRbc9Pt5dWvQa8xUNNcPgPMr6q
AFp6U60hMU5u3eHZoBT26jXmXqR6ZlyP1T4QJF7tQFhvS/+hog7xZZDObwwlPsy5
9/uSKDlDk+J899Pe4hsnOZgKXB0NL2HKIyOhny9eLQWAaHxsrzqr6LqN6KpQAYdI
Dw3MavBawMxfD0bndosauXyGUARybY8fe+MW9EKjkkHpahrWSDJRIN/D59x/5fZL
0lMyvXBDVkspa5iiheEIrHGUFrOo0VibSok+OeNV3IVCLKjA2pko8Vddbssv2Lxw
JuJ2uH2+56RDq+8XD0kIVjImucRIdYsz+9pf4z5sHFI14AcdWLU/hi4piAIHYWjo
8p4KN2OgwKNGbkJVIYyttro9M0fEc30DmDlGZKU=
-----END CERTIFICATE-----
subject=/C=FR/ST=France/L=Paris/O=Maugeri & Co/OU=Maugeri & Co Web Services/CN=www.example.com
issuer=/C=FR/ST=France/O=Maugeri & Co/OU=Maugeri & Co Certificate Authority/CN=Maugeri & Co Intermediate CA
---
No client certificate CA names sent
---
SSL handshake has read 5286 bytes and written 421 bytes
---
New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES256-GCM-SHA384
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
SSL-Session:
Protocol : TLSv1.2
Cipher : ECDHE-RSA-AES256-GCM-SHA384
Session-ID: 282F0F1A393322D5EC760D85B61A3D5316EF7ECA4C22E9EF9CC05FFE82D73259
Session-ID-ctx:
Master-Key: E562CE13B5398E869F7493D1B731506F3B178DAF8AE0142A11A34CD1C88A15496C2BE608129469510EBE083038A8556C
Key-Arg : None
PSK identity: None
PSK identity hint: None
SRP username: None
TLS session ticket lifetime hint: 300 (seconds)
TLS session ticket:
0000 - d2 df 91 71 0e b8 a1 df-c4 3f e4 eb fc d9 fa 26 ...q.....?.....&
0010 - 7d 0e 2f c4 93 22 6d 64-19 f0 ba 3e 98 9f 60 4d }./.."md...>..`M
0020 - fe f6 2a 4b dc 39 bc 31-7f 35 d6 da 93 e6 b5 5e ..*K.9.1.5.....^
0030 - f2 19 26 04 62 44 d4 73-9b 95 a8 6e 2e 72 86 94 ..&.bD.s...n.r..
0040 - 7b 5b 8a bc ac ee 09 71-e8 ec c4 96 e3 89 20 f2 {[.....q...... .
0050 - c2 3b 64 c2 bd 03 a2 cb-a1 2e 66 4f 5b 7d f1 0a .;d.......fO[}..
0060 - 19 05 e1 3a 32 22 e9 03-a6 46 a0 6e d6 0b f1 b9 ...:2"...F.n....
0070 - 52 b6 88 88 98 dd 18 a2-37 37 15 7d 86 39 b5 16 R.......77.}.9..
0080 - 35 e9 87 55 3e 23 c2 19-c3 b8 84 de de 10 e3 5b 5..U>#.........[
0090 - 4e eb 68 a2 55 ff f6 88-f4 1b b9 d9 fa c0 77 ad N.h.U.........w.
00a0 - 58 49 ce a6 59 08 4f 22-64 2f 1f 7d a2 2f 48 06 XI..Y.O"d/.}./H.
Start Time: 1503749297
Timeout : 300 (sec)
Verify return code: 19 (self signed certificate in certificate chain)
---
This is encouraging because I see that the section Certificate chain contains the 3 certificates.
However there is only one PEM presented and these messages do confirm there is something wrong in how the trust chain is presented:
"verify error:num=19:self signed certificate in certificate chain"
"No client certificate CA names sent"
My nginx configuration is:
server {
listen 443;
server_name www.example.com;
root html;
index index.html index.htm;
ssl on;
ssl_certificate /root/ca/intermediate/certs/ca-intermediate-cert-chain.cert.pem;
ssl_certificate_key /root/ca/intermediate/private/www.example.com.key.pem;
[...]
}
}
The file ca-intermediate-cert-chain.cert.pem contains the 3 PEMs in this order (which should be good since nginx starts without error):
-----BEGIN CERTIFICATE-----
[Root CA certificate PEM]
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
[Intermediate CA certificate PEM]
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
[Leaf certificate PEM]
-----END CERTIFICATE-----
Locally I can verify successfully my leaf certificate against the CA:
# openssl verify -CAfile intermediate/certs/ca-intermediate-cert-chain.cert.pem intermediate/certs/www.example.com.cert.pem
intermediate/certs/www.example.com.cert.pem: OK
Do you have any idea on what is wrong in my configuration?
Thanks in advance!
My configuration:
nginx version: nginx/1.4.6 (Ubuntu)
OpenSSL 1.0.1f 6 Jan 2014
This probably has been asked before, but I couldn't find relevant information and this is the first time it happens to me. Trying to capture/decrypt traffic from ASP.NET web application. Web.config modified accordingly to point to Fiddler as a proxy:
<system.net>
<defaultProxy enabled = "true" useDefaultCredentials = "true">
<proxy autoDetect="False" bypassonlocal="False" proxyaddress="http://127.0.0.1:8888" usesystemdefault="False" />
</defaultProxy>
</system.net>
This has worked many times before, but this time Fiddler cannot decrypt HTTPS traffic, getting this:
HTTP/1.1 200 Connection Established
FiddlerGateway: Direct
StartTime: 08:10:40.453
Connection: close
EndTime: 08:10:40.547
ClientToServerBytes: 432
ServerToClientBytes: 3286
This is a CONNECT tunnel, through which encrypted HTTPS traffic flows.
Fiddler's HTTPS Decryption feature is enabled, but this specific tunnel was configured not to be decrypted. Settings can be found inside Tools > Fiddler Options > HTTPS.
A SSLv3-compatible ServerHello handshake was found. Fiddler extracted the parameters below.
Version: 3.1 (TLS/1.0)
SessionID: 54 87 1E 5C 03 C7 16 81 E6 25 E8 8F 48 C0 42 52 23 B6 5B 04 4F 4D 69 67 11 F2 9E 09 D0 27 77 2D
Random: 54 87 1F 00 0D 37 FF 22 3E 6A 10 BF 4D 4F 67 ED C2 D2 97 A9 66 B2 CF 56 0D 8C 7C E5 6B 2E 2E A1
Cipher: TLS_RSA_AES_128_SHA [0x002F]
CompressionSuite: NO_COMPRESSION [0x00]
Extensions:
renegotiation_info 00
Any idea what is going on here and how to make Fiddler decrypt traffic?
I'm trying to call an API using Network.HTTP.Client and am trying to figure out how to properly handle a TlsNotSupported exception and call the API over SSL. There are no examples in the documentation and there are not (surprisingly) any examples I can find elsewhere on the web.
Here is my existing code:
module Main where
import Network.URL
import qualified Network.URI as URI
import qualified Network.HTTP as HTTP
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as LBS
import qualified Data.ByteString.Base64 as B64
import qualified Network.HTTP.Client as HTTPClient
import qualified Network.HTTP.Types.Header as HTTPHeaders
import qualified Data.ByteString.Char8 as C
import qualified Network.HTTP.Types.Status as HTTPStatus
import qualified Data.Text as T
import qualified Control.Exception as E
import qualified Data.Text.Encoding as TE
import Data.Aeson
import Control.Applicative ((<*>), (<$>), pure)
import Control.Monad (mzero)
data Bookmark = Bookmark {
url :: T.Text,
title :: Maybe T.Text
} deriving Show
data Note = Note {
author :: T.Text,
text :: T.Text
} deriving Show
instance FromJSON Bookmark where
parseJSON (Object v) = Bookmark <$>
v .: T.pack "href" <*>
v .: T.pack "description"
parseJSON _ = mzero
b64Encode :: String -> String
b64Encode = T.unpack . TE.decodeUtf8 . B64.encode . TE.encodeUtf8 . T.pack
basicAuthHeader :: String -> String -> String
basicAuthHeader username password = "Authorization: " ++
b64Encode (username ++ ":" ++ username)
postsURL token = "https://api.pinboard.in/posts/all?format=json&auth_token=" ++ token
parse :: BS.ByteString -> Maybe [Bookmark]
parse response = decode (LBS.fromStrict response)
transform = LBS.fromStrict . C.pack
errorHandler :: HTTPClient.HttpException -> IO (Maybe a)
errorHandler (HTTPClient.StatusCodeException status _ _) = return Nothing
errorHandler (HTTPClient.InvalidUrlException _ _) = return Nothing
errorHandler (HTTPClient.HttpParserException _) = return Nothing
errorHandler e = do
case e of
HTTPClient.TlsNotSupported -> (putStrLn $ "Bummer. " ++ show e) >> return Nothing
main = do
putStrLn "Enter auth token: "
token <- getLine
manager <- HTTPClient.newManager HTTPClient.defaultManagerSettings
request <- HTTPClient.parseUrl $ postsURL token
putStrLn $ "Calling " ++ postsURL token
response <- (Just <$> HTTPClient.httpLbs request manager) `E.catch` errorHandler
return ()
Here's an example session:
$ runhaskell Pinboard.hs
Enter auth token:
blah
Calling https://api.pinboard.in/posts/all?format=json&auth_token=asd
Bummer. TlsNotSupported
Thanks in advance!
You need to use http-client-tls. In particular, replace your usage of defaultManagerSettings with tlsManagerSettings.
Calling https://api.pinboard.in/posts/all?format=json&auth_token=asd
Bummer. TlsNotSupported
I'm getting a different result. It appears TLS is supported.
Are you using Gandi Standard SSL CA or UTN-USERFirst-Hardware as a trust anchor?
$ echo -e "GET /posts/all?format=json&auth_token=asd HTTP/1.1\r\nHost:api.pinboard.in\r\n\r\n" | \
openssl s_client -tls1 -connect api.pinboard.in:443 -servername api.pinboard.in -ign_eof
CONNECTED(00000003)
depth=1 C = FR, O = GANDI SAS, CN = Gandi Standard SSL CA
verify error:num=20:unable to get local issuer certificate
verify return:0
---
Certificate chain
0 s:/OU=Domain Control Validated/OU=Gandi Standard Wildcard SSL/CN=*.pinboard.in
i:/C=FR/O=GANDI SAS/CN=Gandi Standard SSL CA
1 s:/C=FR/O=GANDI SAS/CN=Gandi Standard SSL CA
i:/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN-USERFirst-Hardware
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIE4zCCA8ugAwIBAgIRAJhTQpn18jrbs6EACUBuCEEwDQYJKoZIhvcNAQEFBQAw
QTELMAkGA1UEBhMCRlIxEjAQBgNVBAoTCUdBTkRJIFNBUzEeMBwGA1UEAxMVR2Fu
ZGkgU3RhbmRhcmQgU1NMIENBMB4XDTEzMDgwNTAwMDAwMFoXDTE1MDkwMzIzNTk1
OVowYTEhMB8GA1UECxMYRG9tYWluIENvbnRyb2wgVmFsaWRhdGVkMSQwIgYDVQQL
ExtHYW5kaSBTdGFuZGFyZCBXaWxkY2FyZCBTU0wxFjAUBgNVBAMUDSoucGluYm9h
cmQuaW4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCmwELG8RLaC+PD
YRSORwf5dZ+OGDFNnot9It+nEJh3Y9e95y2xxfQQnMfGcrj4UdMNx6Vie2Baz3yD
hU6hweT5ZlpWA43u7xoF2DP5NsgktcTZzQ+IZ124uVvDs+Q5LAH6/aHUplzmdZDz
xDM9JSz8pxXmS9HSJmR1tamYi9B+d30/yxHPibe62Ku6FQ4yoa+f2GVGdvqqvvpZ
7gbwBgu6PKLVNRQPrhUdjdgEj0h44/4DZ/sUw3Jw2cti0yELh4eDLgXonvqCUrOQ
79NJTEzqBBHBUER0ltdUbCXczAm5IQk4pTzSUaI5rML/fcphBaWh0t0XSg9cMFAl
biNqpr9tAgMBAAGjggG0MIIBsDAfBgNVHSMEGDAWgBS2qP+iqC/Qps1LsWjz51AQ
Mad5ITAdBgNVHQ4EFgQUzuFnVq27SbN342v9mBiEc7tygJIwDgYDVR0PAQH/BAQD
AgWgMAwGA1UdEwEB/wQCMAAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC
MGAGA1UdIARZMFcwSwYLKwYBBAGyMQECAhowPDA6BggrBgEFBQcCARYuaHR0cDov
L3d3dy5nYW5kaS5uZXQvY29udHJhY3RzL2ZyL3NzbC9jcHMvcGRmLzAIBgZngQwB
AgEwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5nYW5kaS5uZXQvR2FuZGlT
dGFuZGFyZFNTTENBLmNybDBqBggrBgEFBQcBAQReMFwwNwYIKwYBBQUHMAKGK2h0
dHA6Ly9jcnQuZ2FuZGkubmV0L0dhbmRpU3RhbmRhcmRTU0xDQS5jcnQwIQYIKwYB
BQUHMAGGFWh0dHA6Ly9vY3NwLmdhbmRpLm5ldDAlBgNVHREEHjAcgg0qLnBpbmJv
YXJkLmluggtwaW5ib2FyZC5pbjANBgkqhkiG9w0BAQUFAAOCAQEAn9i7ilujiOhL
QKMAAuS7xWTvERddqjnnOPBwUw7FCd+VaEnpNCCjqxwrTdWjm4MkjtN2HfDesw1c
IqpLVAMNn35m3aqu7fvyCbBKCkjXLnj1TuKsd/IIFJuqgHNjqyvfe6IIW/Mss+Qq
2TUmVF0HLF2+fyihsdYTlqcv5bR/X7dwbFi1xecoMaDf6K8TTiEKjmr2wNWuKRGy
TsWTqMPBPkyHBJPL589/ETBvqvx1cu/CU81hiadlVino/Buha0cDjNYZra2gOfRR
U2+vK9tsN9Ct0lfOYAamHSiIwGD1HfzdV8xItmZSNsLm3jBZQ1bsqN82+9n2CKWG
IS0WjmfyaA==
-----END CERTIFICATE-----
subject=/OU=Domain Control Validated/OU=Gandi Standard Wildcard SSL/CN=*.pinboard.in
issuer=/C=FR/O=GANDI SAS/CN=Gandi Standard SSL CA
---
No client certificate CA names sent
---
SSL handshake has read 3332 bytes and written 438 bytes
---
New, TLSv1/SSLv3, Cipher is DHE-RSA-AES256-SHA
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
SSL-Session:
Protocol : TLSv1
Cipher : DHE-RSA-AES256-SHA
Session-ID: C4D0B1D4C4DA50734AFA09A3675A9A6828053B022A516F53E6C2BEA303C49AFC
Session-ID-ctx:
Master-Key: 34A2E6C6B1D17AE7214380462438E9C670CA1E8F9E719D0DEFB7EDE1EC87D847D1DF317523BAAE05278A10E1EDAE51C5
Key-Arg : None
PSK identity: None
PSK identity hint: None
SRP username: None
TLS session ticket lifetime hint: 300 (seconds)
TLS session ticket:
0000 - 15 99 b9 ce d4 d9 bc 6f-d5 4b 12 83 cd 6f eb b0 .......o.K...o..
0010 - f6 37 a3 66 21 ea ff d1-cf 73 56 fa 25 99 61 1c .7.f!....sV.%.a.
0020 - 38 15 a6 e9 e8 47 cc f8-2b df 8d 64 68 13 1c be 8....G..+..dh...
0030 - 8d 8a 32 a5 ca dd 79 d7-f6 d0 0c 1e e4 50 01 64 ..2...y......P.d
0040 - 73 3e 9f 34 42 3d 4d 56-a3 cc 09 d8 aa 7b 2a 82 s>.4B=MV.....{*.
0050 - 5d 96 c3 1f 3e 19 48 c7-90 c6 4c 07 75 15 e5 42 ]...>.H...L.u..B
0060 - 13 31 c1 fc b4 cc 5f 8e-0b a1 cd 5f bc 7a 16 9c .1...._...._.z..
0070 - 24 3c 5b e7 52 97 ce 15-4f b1 01 44 dc 72 35 82 $<[.R...O..D.r5.
0080 - 4e c9 f9 19 69 26 1c 82-44 f5 c0 6a 57 99 54 da N...i&..D..jW.T.
0090 - cf a8 f4 6f 6b ab c6 ec-98 c6 91 31 d1 20 5c 5c ...ok......1. \\
00a0 - 0f 94 42 5a 8f f5 f7 0d-cd 31 71 04 66 89 5f c1 ..BZ.....1q.f._.
00b0 - 00 84 cd 9e c1 99 52 4f-c0 1e 43 25 f2 36 b9 28 ......RO..C%.6.(
Start Time: 1408986495
Timeout : 7200 (sec)
Verify return code: 20 (unable to get local issuer certificate)
---
HTTP/1.1 403 Forbidden
Date: Mon, 25 Aug 2014 17:07:55 GMT
Server: Apache/2.2.22 (Ubuntu)
Vary: Accept-Encoding
Content-Length: 292
Content-Type: text/html; charset=iso-8859-1
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>403 Forbidden</title>
</head><body>
<h1>Forbidden</h1>
<p>You don't have permission to access /posts/all
on this server.</p>
<hr>
<address>Apache/2.2.22 (Ubuntu) Server at api.pinboard.in Port 80</address>
</body></html>
read:errno=0
riemann::~$
Out of curiosity, I spent some time looking through TCP dumps of an https web connection I made. I have been able to make sense of most of it, but I am stuck on one particular TLS Record. Here is the hex dump:
16 03 01 00 24 ae f5 83 cb 35 db dd 67 f5 bf 4a
c7 52 b5 16 56 59 52 40 fa 7b f8 f6 40 a7 13 74
0a f3 b0 6e 5b 4f 2b 88 a3
The previous Record is a Change Cipher Spec Record (i.e. Content Type 0x14) if that helps. Also, I used wget to make the request.
As far as I can tell, this should follow the handshake subprotocol (16), uses TLS 1.0 (03 01), the message length is 36 Bytes (00 24). And here is where I am stuck: what does the ae mean?! At first I thought it might have something to do with SNI or some other TLS extension, but so far no luck there either.
Any help interpreting this would be appreciated.
There is no HandshakeType with a value of 174. The 174 shows up because the TLS connection just finished negotiating a cipher suite, and is now encrypting the record's payload!