How to transform a jwk to public key over openssl - encryption

I have a JWE and in header an ephemeral public key.
So I have coordinate X and Y.
My question in shell mode how to convert the JWK to ECC public key in pem format.
For example, here a jwk
{"epk":{"kty":"EC","crv":"P-256","x":"GCl--lQHb7NKYU3jXpKVI_BYaTlALT5JFPdl3sbB9mY","y":"ADRX25PBSlZJE79drET0ARtRqZAkUIMNt9aa2bbjBYY"}}
After I do this
> # I convert the x coordonate from base64url to base64
> echo -n -e "GCl++lQHb7NKYU3jXpKVI/BYaTlALT5JFPdl3sbB9mY" | base64 -d | hexdump
0000000 2918 fa7e 0754 b36f 614a e34d 925e 2395
0000010 58f0 3969 2d40 493e f714 de65 c1c6 66f6
0000020
> echo -n -e "ADRX25PBSlZJE79drET0ARtRqZAkUIMNt9aa2bbjBYY" | base64 -d | hexdump
0000000 3400 db57 c193 564a 1349 5dbf 44ac 01f4
0000010 511b 90a9 5024 0d83 d6b7 d99a e3b6 8605
0000020
So the public key is
04
2918 fa7e 0754 b36f 614a e34d 925e 2395
58f0 3969 2d40 493e f714 de65 c1c6 66f6
3400 db57 c193 564a 1349 5dbf 44ac 01f4
511b 90a9 5024 0d83 d6b7 d99a e3b6 8605
But I have the curve, the public key, I want to know how to generate a pem?
In other words,
I have a file mykey.pub which contains this:
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAETGUwowNEfqQ0LtHiMXJPY+Os5pXc
lsYCRPOi3F6K0n4k1RjJ7PGp/9RhZy3XS1yn1Qlu4hoCClHcc9rPXPn4fQ==
-----END PUBLIC KEY-----
I execute this command to display the public key:
> openssl ec -in mykey.pub -pubin -text -noout
read EC key
Public-Key: (256 bit)
pub:
04:4c:65:30:a3:03:44:7e:a4:34:2e:d1:e2:31:72:
4f:63:e3:ac:e6:95:dc:96:c6:02:44:f3:a2:dc:5e:
8a:d2:7e:24:d5:18:c9:ec:f1:a9:ff:d4:61:67:2d:
d7:4b:5c:a7:d5:09:6e:e2:1a:02:0a:51:dc:73:da:
cf:5c:f9:f8:7d
ASN1 OID: prime256v1
NIST CURVE: P-256
So my question is if I have this data
> openssl ec -in mykey.pub -pubin -text -noout
read EC key
Public-Key: (256 bit)
pub:
04:4c:65:30:a3:03:44:7e:a4:34:2e:d1:e2:31:72:
4f:63:e3:ac:e6:95:dc:96:c6:02:44:f3:a2:dc:5e:
8a:d2:7e:24:d5:18:c9:ec:f1:a9:ff:d4:61:67:2d:
d7:4b:5c:a7:d5:09:6e:e2:1a:02:0a:51:dc:73:da:
cf:5c:f9:f8:7d
ASN1 OID: prime256v1
NIST CURVE: P-256
how to retrieve this in shell mode
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAETGUwowNEfqQ0LtHiMXJPY+Os5pXc
lsYCRPOi3F6K0n4k1RjJ7PGp/9RhZy3XS1yn1Qlu4hoCClHcc9rPXPn4fQ==
-----END PUBLIC KEY-----

Let me first briefly describe your target format. What you are seeking to obtain is a PEM encoded SubjectPublicKeyInfo (SPKI) file. PEM encoding is essentially DER encoding (which is a binary format) and then base64 encoded with a header and footer. The SPKI structure is defined in RFC5280 (see section 4.1):
https://www.rfc-editor.org/rfc/rfc5280#section-4.1
SubjectPublicKeyInfo ::= SEQUENCE {
algorithm AlgorithmIdentifier,
subjectPublicKey BIT STRING }
So the first chunk of bytes in the binary DER encoding consists of a header that identifies the algorithm being used (and part of that includes the curve). The last bytes are the raw public key (which is an encoded x and y co-ordinate on the curve).
Since your sample key is for the same curve as the key you want to create it will have the same AlgorithmIdentifier header bytes. Taking your mykey.pub file we can convert it to the binary DER format:
$ openssl ec -in mykey.pub -pubin -outform DER -out key.der
Lets look at the contents:
$ hexdump -C key.der
00000000 30 59 30 13 06 07 2a 86 48 ce 3d 02 01 06 08 2a |0Y0...*.H.=....*|
00000010 86 48 ce 3d 03 01 07 03 42 00 04 4c 65 30 a3 03 |.H.=....B..Le0..|
00000020 44 7e a4 34 2e d1 e2 31 72 4f 63 e3 ac e6 95 dc |D~.4...1rOc.....|
00000030 96 c6 02 44 f3 a2 dc 5e 8a d2 7e 24 d5 18 c9 ec |...D...^..~$....|
00000040 f1 a9 ff d4 61 67 2d d7 4b 5c a7 d5 09 6e e2 1a |....ag-.K\...n..|
00000050 02 0a 51 dc 73 da cf 5c f9 f8 7d |..Q.s..\..}|
0000005b
You can see the first bytes of the public key that you printed out above starting at offset 0x1a (i.e. 26 bytes in): 04 4c 65 30 .... The raw public key data extends all the way the end of the file and is 65 bytes long. This consists of a leading 0x04 byte followed by 32 bytes of x co-ordinate and 32 bytes of y co-ordinate. The leading 0x04 tells us how the co-ordinate is represented. 0x04 means "uncompressed" - which is handy because that's the simplest for us to deal with. We will also use uncompressed format for our target key. Therefore we need to take the first 26 bytes of header plus the 0x04 byte (so 27 bytes in total) from our sample key:
$ head -c 27 key.der >key.head
And just to check we got what we were expecting:
$ hexdump -C key.head
00000000 30 59 30 13 06 07 2a 86 48 ce 3d 02 01 06 08 2a |0Y0...*.H.=....*|
00000010 86 48 ce 3d 03 01 07 03 42 00 04 |.H.=....B..|
0000001b
Now we create the x and y elements of our co-ordinate, which you already did:
$ echo -n "GCl++lQHb7NKYU3jXpKVI/BYaTlALT5JFPdl3sbB9mY=" | base64 -d >key.x
$ echo -n "ADRX25PBSlZJE79drET0ARtRqZAkUIMNt9aa2bbjBYY=" | base64 -d >key.y
And then put all the elements together:
cat key.head key.x key.y >keynew.der
We can convert the new key in DER format to PEM format:
$ openssl ec -in keynew.der -inform DER -pubin -out keynew.pem
Which gives us:
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEGCl++lQHb7NKYU3jXpKVI/BYaTlA
LT5JFPdl3sbB9mYANFfbk8FKVkkTv12sRPQBG1GpkCRQgw231prZtuMFhg==
-----END PUBLIC KEY-----
And just to check it looks sane:
$ openssl ec -in keynew.pem -pubin -noout -text
read EC key
Public-Key: (256 bit)
pub:
04:18:29:7e:fa:54:07:6f:b3:4a:61:4d:e3:5e:92:
95:23:f0:58:69:39:40:2d:3e:49:14:f7:65:de:c6:
c1:f6:66:00:34:57:db:93:c1:4a:56:49:13:bf:5d:
ac:44:f4:01:1b:51:a9:90:24:50:83:0d:b7:d6:9a:
d9:b6:e3:05:86
ASN1 OID: prime256v1
NIST CURVE: P-256

Related

Manually created signature in certificate signing request is not matching with the openssl req generated signature

Created certificate signing request using following commands :
$ openssl genrsa -out test.key 2048
$ openssl req -new -key test.key -subj "/CN=foo" -out foo.csr
with the help of steps provided #marc i have extracted 4 files from it :
info.der ( openssl asn1parse -in foo.csr -strparse 4 -out info.der )
pub.pem (openssl req -pubkey -in foo.csr -noout -out pub.pem)
hash.manual ( saved hex output of command "sha256 info.der")
sig.raw (openssl asn1parse -in foo.csr -strparse 338 -out sig.raw )
My understanding / doubt is , "Signature" mentioned in foo.csr is nothing but "encrypted ouptut" of the "hash.manual" with private key "test.key". so to validate my understanding i used
$ openssl rsautl -encrypt -in hash_manual -inkey test.key -out manual_signature
Now when i perform diff on these two files they are not matching and hexdump -C confirms the sig.raw is matching the signature output mentioned in (openssl req -in csr --text).
Please help in clarifying why manual_signature & sig.raw are not matching.
You have two problems:
you need to use sign rather than encrypt. For RSA, encrypt is encryption with the public key but sign is encryption with the private key
the output of rsautl is in the wrong format
The first is easy to fix, just use -sign.
The second is a bit more annoying, it is not just the sha256 output being signed, it's an ASN.1 structure that looks like this:
0:d=0 hl=2 l= 49 cons: SEQUENCE
2:d=1 hl=2 l= 13 cons: SEQUENCE
4:d=2 hl=2 l= 9 prim: OBJECT :sha256
15:d=2 hl=2 l= 0 prim: NULL
17:d=1 hl=2 l= 32 prim: OCTET STRING
0000 - dc 31 c9 99 51 ce 03 a2-aa 14 13 f1 c4 f6 3e ea .1..Q.........>.
0010 - 4f 87 a2 56 37 de 7f a7-c1 87 49 f0 43 c9 ba bb O..V7.....I.C...
Where the final OCTET STRING field is the raw sha256 hash.
The easiest way to generate this is to use openssl dgst to combine hashing and signature:
# Hash and sign the certificationRequestInfo
$ openssl dgst -sha256 -sign test.key info.der > manual_signature
# Compare to extracted sig.raw (no output means no diff)
$ diff manual_signature sig.raw
# Verify both the extracted sig.raw and the manual_signature using the public key
$ openssl rsautl -verify -pubin -inkey pub.pem -in sig.raw -asn1parse
0:d=0 hl=2 l= 49 cons: SEQUENCE
2:d=1 hl=2 l= 13 cons: SEQUENCE
4:d=2 hl=2 l= 9 prim: OBJECT :sha256
15:d=2 hl=2 l= 0 prim: NULL
17:d=1 hl=2 l= 32 prim: OCTET STRING
0000 - dc 31 c9 99 51 ce 03 a2-aa 14 13 f1 c4 f6 3e ea .1..Q.........>.
0010 - 4f 87 a2 56 37 de 7f a7-c1 87 49 f0 43 c9 ba bb O..V7.....I.C...
$ openssl rsautl -verify -pubin -inkey pub.pem -in manual_signature -asn1parse
0:d=0 hl=2 l= 49 cons: SEQUENCE
2:d=1 hl=2 l= 13 cons: SEQUENCE
4:d=2 hl=2 l= 9 prim: OBJECT :sha256
15:d=2 hl=2 l= 0 prim: NULL
17:d=1 hl=2 l= 32 prim: OCTET STRING
0000 - dc 31 c9 99 51 ce 03 a2-aa 14 13 f1 c4 f6 3e ea .1..Q.........>.
0010 - 4f 87 a2 56 37 de 7f a7-c1 87 49 f0 43 c9 ba bb O..V7.....I.C...

Deploying SSL certificate with private Root/Intermediate CA - trust chain not shown completly

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

What all encryption uses == in the last?

I am aware that most of the Base64 encoding has == at the end. Is there any other which uses does the same?
For example, I found this:
nijdRcCHIUnketWzFbcxmvqQKKDnFW05LSE3ttTjoqyBna7JT87AwxeKdoOszXYODMRm6UfA8jK97qgV8A==
But it is not a Base64 kind. What else can it be?
The string you have posted is a valid Base64 string.
A Base64 string will end with == if and only if the number of bytes it encodes, mod 3, equals 1.
>>> for i in range(10):
... print(i, base64.b64encode(b"\x00"*i))
...
0 b''
1 b'AA=='
2 b'AAA='
3 b'AAAA'
4 b'AAAAAA=='
5 b'AAAAAAA='
6 b'AAAAAAAA'
7 b'AAAAAAAAAA=='
8 b'AAAAAAAAAAA='
9 b'AAAAAAAAAAAA'
Do you see the pattern?
It happens that 16-byte (128-bit) encryption keys are very commonly encoded in Base64, and since 16 mod 3 = 1, their encoding will end with ==. But your string, decoded, is 61 bytes (488 bits) long. That is too big to be most sorts of encryption key, and too small to be an RSA key.
This is your string, decoded, and then hexdumped:
00000000 9e 28 dd 45 c0 87 21 49 e4 7a d5 b3 15 b7 31 9a |.(.E..!I.z....1.|
00000010 fa 90 28 a0 e7 15 6d 39 2d 21 37 b6 d4 e3 a2 ac |..(...m9-!7.....|
00000020 81 9d ae c9 4f ce c0 c3 17 8a 76 83 ac cd 76 0e |....O.....v...v.|
00000030 0c c4 66 e9 47 c0 f2 32 bd ee a8 15 f0 |..f.G..2.....|
0000003d
I don't see anything in there to tell me what it actually is, and file(1) is also stumped. It could be random enough to be encrypted, but I can't tell for sure by eye. (And if it is random, that doesn't mean it's encrypted! It could just be the output of a random number generator.)
It is important to understand that Base64 is not encryption, because it has no key. I didn't need to know or guess any piece of secret information to reverse the Base64 encoding of your string. (The term 'encoding' can be confusing — it is more general. UTF-8, Base64, and DEFLATE are all encodings, and so is AES-CBC, but of all of them, only AES-CBC is encryption.)

How to handle TlsNotSupported and call an HTTPS URL with Network.HTTP.Client?

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::~$

Certificate signature verification on Microchip PIC controllers

I'm trying to implement certificate signature verification on a Microchip pic controller (certificates are generated and signed using OpenSSL). The Microchip PIC controller doesn't support OpenSSL libraries, but it does have an encryption/decryption function. I was successful in getting a SSL connection between PIC controller and a web server. My next step is to setup signature verification on the PIC controller.
After reading PKCS#1 V2.1 RSA Cryptography Standard (http://www.rsa.com/rsalabs/node.asp?id=2125)
I realized that encryption is essentially the same as signature verification and decryption is the same as signing. More specifically both encryption and verification uses the public key and the following formula:
m = s ^ e mod n
Where s is the signature or the message, e is the public exponent, n is the modulus and m is the encrypted message or decoded signature. Therefore, I'm trying to use the encryption algorithm provided to perform signature verification.
In order to verify the certificate, I generated the SHA1 hash of the certificate; Decoded signature using CA's public key and encryption algorithm. Remove the padding from the decoded signature, the result hash should be equal to the SHA1 hash of the certificate.
However, I cannot get the two hash values to be equal. I tried to verify my assumption and PIC controller results using OpenSSL command line.
This is the hash value I got from both OpenSSL command line and PIC controller
openssl rsautl -in signature.txt -verify -asn1parse -inkey pubkey.pem
-pubin
db e8 c6 cb 78 19 3c 0f-fd 96 1c 4f ed bd b2 34 45 60 bf 65
This is what I got from Signature verification using OpenSSL. After removing "ff" paddings I'll end up with asn1 format of the certificate hash.
openssl rsautl -verify -in signature.txt -inkey pubkey.pem -pubin
-raw -hexdump
00 01 ff ff ff ff ff ff-ff ff ff ff 00 30 21 30
09 06 05 2b 0e 03 02 1a-05 00 04 14 db e8 c6 cb
78 19 3c 0f fd 96 1c 4f-ed bd b2 34 45 60 bf 65
However this is what I got from the PIC controller which is much different from the above
8e fb 62 0e 09 c8 0b 49 40 1f 4d 2d a7 7d d6 8c
9b bc 95 e6 bc 98 4b 96 aa 74 e5 68 90 40 bf 43
b5 c5 02 6d ab e3 ad 7b e6 98 fd 10 22 af b9 fb
This is my signature
7951 9b3d 244a 37f6 86d7 dc02 dc18 3bb4
0f66 db3a a3c1 a254 5be5 11d3 a691 63ef
0cf2 ec59 c48b 25ad 8881 9ed2 5230 bcd6
This is my public key (I'm using a very small key just for testing, will make it larger once everything works)
96 FE CB 59 37 AE 8C 9C 6C 7A 01 50 0F D6 4F B4
E2 EC 45 D1 88 4E 1F 2D B7 1E 4B AD 76 4D 1F F1
B0 CD 09 6F E5 B7 43 CA F8 14 FE 31 B2 06 F8 7B
Exponent is 01 00 01
I'm wondering are my assumptions wrong that I cannot use encryption algorithm for decoding signature? or I'm doing something else wrong?
It turned out the method I described above is correct. I was able to get the matching result from hashing the certificate and unsigning the signature using encryption.
The problem that caused my previous failing attempts was the endianess used by Microchip Pic controller. They use small-endian instead of big-endian. I did not pay attention to the endianness of the exponent since 01 00 01 is the same in either format. However I was wrong, it turns out Microchip looks at a 4 byte value as the exponent (RSA standard??). So it pads 00 in the front resulting 00 01 00 01. Therefore, the endianness matters now since 00 01 00 01 is different from 01 00 01 00. And 01 00 01 00 is the small-endian format that Microchip Pic uses.

Resources