Difference between revisions of "OpenID-eID"

From YobiWiki
Jump to navigation Jump to search
 
(26 intermediate revisions by 2 users not shown)
Line 3: Line 3:
 
===Install packages===
 
===Install packages===
 
Let's get apache2, php5 and openssl stuff:
 
Let's get apache2, php5 and openssl stuff:
apt-get install apache2-utils apache2-mpm-prefork libapache2-mod-php5 php5 openssl ssl-cert
+
apt-get install apache2-utils apache2-mpm-prefork libapache2-mod-php5 php5 openssl ssl-cert opensc
   
 
===Setup apache server with SSL===
 
===Setup apache server with SSL===
Line 36: Line 36:
 
pkcs15-tool --read-certificate 04 > /etc/apache2/ssl/ca/belgium.crt
 
pkcs15-tool --read-certificate 04 > /etc/apache2/ssl/ca/belgium.crt
 
pkcs15-tool --read-certificate 06 >> /etc/apache2/ssl/ca/belgium.crt
 
pkcs15-tool --read-certificate 06 >> /etc/apache2/ssl/ca/belgium.crt
  +
Note that with recent cards I had to add the GlobalSign certificate too.
Then add client certificate requirements to /etc/apache2/sites-available/default-ssl
+
<br>Then add client certificate requirements to /etc/apache2/sites-available/default-ssl
 
SSLCACertificateFile /etc/apache2/ssl/ca/belgium.crt
 
SSLCACertificateFile /etc/apache2/ssl/ca/belgium.crt
 
SSLOptions +StrictRequire
 
SSLOptions +StrictRequire
Line 42: Line 43:
 
SSLVerifyDepth 10
 
SSLVerifyDepth 10
 
<Location />
 
<Location />
# accept only certificates emitted by Citizen CA:
+
# accept only certificates emitted by Citizen CA or Foreigner CA:
SSLRequire %{SSL_CLIENT_I_DN_C} eq "BE" \
+
SSLRequire %{SSL_CLIENT_I_DN_C} eq "BE" \
and %{SSL_CLIENT_I_DN_CN} in {"Citizen CA"}
+
and ( %{SSL_CLIENT_I_DN_CN} in {"Citizen CA"} \
  +
or %{SSL_CLIENT_I_DN_CN} in {"Foreigner CA"} )
 
</Location>
 
</Location>
 
According to the doc, because of a bug in Internet Explorer, you also need to add GlobalSign Root certificate...
 
According to the doc, because of a bug in Internet Explorer, you also need to add GlobalSign Root certificate...
  +
  +
Xavier Dury proposed to use directly his eID to access a specific directory on an Apache server by "abusing" the Location directive above:
  +
<br>You can add sth like SSLRequire %{SSL_CLIENT_S_DN} but beware of the format of the DN string, it's not the same as with openssl. It should look like "/C=BE/CN=My Name..." and not "C=BE, CN=My Name...".
  +
<br>Moreover special characters must be encoded & protected, e.g. Sébastien has to be coded as <code>S\\xC3\\xA9bastien</code>.
  +
 
===Retrieving citizens' certificate information===
 
===Retrieving citizens' certificate information===
The REMOTE_USER header can be used.
+
The user's distinguish name can be retrieved from php with
 
$_SERVER['SSL_CLIENT_S_DN']
<br>To set it to the user's distinguish name:
 
 
And the user's name with
SSLUserName SSL_CLIENT_S_DN
 
  +
$_SERVER['SSL_CLIENT_S_DN_CN']
Or the user's national number:
 
  +
If those variables are not exported in your environment, check if StdEnvVars is in your Apache SSLOptions for all scripts. On a regular Debian I get:
SSLUserName SSL_CLIENT_S_DN_serialNumber
 
  +
<pre>
  +
<FilesMatch "\.(cgi|shtml|phtml|php)$">
  +
SSLOptions +StdEnvVars
  +
</FilesMatch>
  +
<Directory /usr/lib/cgi-bin>
  +
SSLOptions +StdEnvVars
  +
</Directory>
  +
</pre>
   
 
===TODO: cf [http://www.belgium.be/zip/eid_authentication_proxy_fr.html apache SSL reverse proxy] proposed by the government===
 
===TODO: cf [http://www.belgium.be/zip/eid_authentication_proxy_fr.html apache SSL reverse proxy] proposed by the government===
Line 60: Line 75:
 
SSLForceValidation on
 
SSLForceValidation on
 
* [http://issues.apache.org/bugzilla/show_bug.cgi?id=35083 Certificate validation problems trapping]
 
* [http://issues.apache.org/bugzilla/show_bug.cgi?id=35083 Certificate validation problems trapping]
  +
Enable ssl_error_module:
Add to /etc/apache2/sites-available/default-ssl:
 
  +
LoadModule ssl_error_module modules/mod_ssl_error.so
 
And add to /etc/apache2/sites-available/default-ssl:
  +
<IfModule mod_ssl_error.c>
 
SSL_Error_DefaultURL "/error/invalid.html"
 
SSL_Error_DefaultURL "/error/invalid.html"
 
SSL_Error_URL 23 "/error/revoked.html"
 
SSL_Error_URL 23 "/error/revoked.html"
 
SSL_Error_URL 10 "/error/expired.html"
 
SSL_Error_URL 10 "/error/expired.html"
  +
</IfModule>
  +
cf doc...
  +
* Or simply make the client certificate as optional and test for it in php
   
 
===Hacking [http://siege.org/projects/phpMyID/ phpMyID]===
 
===Hacking [http://siege.org/projects/phpMyID/ phpMyID]===
Line 70: Line 91:
 
* remove HTTP Digest for the authorization step
 
* remove HTTP Digest for the authorization step
 
* redirect authorization to HTTPS as we'll deal with SSL client certificates
 
* redirect authorization to HTTPS as we'll deal with SSL client certificates
  +
* TODO
  +
* [http://id.yobi.be/MyID.phps current source code of the hacked phpMyID]
  +
  +
Status:
  +
* I could validate the client certificate against the root CA and I could extract the data of the certificate
  +
* I could create various OpenIDs based on the certificate data<br>Everything is extracted only from the names and RRN, not on the serial nr of the certificate or any part prone to be changed if you've to renew your ID card! (unless they change the way they write your name on the certificate...)
  +
* I still consider RRN as sensitive data so the IDs I can provide must be a balance between several factors:
  +
** friendliness (easy to remember)
  +
** displaying your name or not?
  +
** avoid clashes
  +
** RRN retrieval more or less robust against brute force retrieval
  +
* So '''about security & clashes''', the hash is very very safe, the others, well, it depends how likely is your name...
  +
* I added a discover mode which tells you what are your OpenIDs given your own eID, you can try here:
  +
http://id.yobi.be/?openid.mode=discover
  +
# This will return in my case:
  +
http://id.yobi.be/?id=ae96fba0cd9515cd
  +
http://id.yobi.be/?id=philippe.teuwen.159
  +
http://id.yobi.be/?id=philippe.yvon.teuwen
  +
Another kind of ID could be
  +
id=firstname.lastname.Hash(RRN|firstname2|initial3|firstname|lastname)
  +
So it tells your name but still hides RRN is a moderately hard to brute-force hash as you've to guess RRN but also your second firstname & initial of the third firstname (if you've a single firstname you're out of luck, I've 5 firstnames!)
  +
  +
Estonian [https://openid.ee/about/english counterpart] plans to provide simply firstname.lastname and to build an index in case of clashes.<br>
  +
But this requires to have a stateful server and I don't want that, I want anybody to build his own service and the generated OpenIDs will always be the same, only depending on the certificate data, not on "who came first".<br>Otherwise imagine the mess if the server data gets destroyed!
  +
* My OpenIDs are now valid and successfully tested with e.g. [http://www.openidenabled.com/resources/openid-test/checkup/start?openid_url=http%3A%2F%2Fid.yobi.be%2F%3Fid%3Dae96fba0cd9515cd this OpenID checking server]
  +
  +
Todo:
  +
* CRL & cf TODO patches above
  +
* Maybe some stateful stuff on the server for minor info: pavatar, microid...
  +
* Check if server is able to do stateful associations
  +
* Support also for CAcert client certificates, be our own CA?
  +
* Clean-up server and delegate URLs
  +
** e.g. http://id.yobi.be & http://id.yobi.be/ae96fba0cd9515cd (or xri?)
  +
* Move to php-openid
  +
Security:
  +
* If someone knows your name and your partial hash he can bruteforce your RRN (and your middle name if the attacker didn't get it) but is RRN a secret anymore? Given any email you signed with your eID is enough to simply extract (and not bruteforce) your RRN...

Latest revision as of 00:26, 21 July 2012

Here are my attempts to create an OpenID provider based on the Belgian eID

Install packages

Let's get apache2, php5 and openssl stuff:

apt-get install apache2-utils apache2-mpm-prefork libapache2-mod-php5 php5 openssl ssl-cert opensc

Setup apache server with SSL

Create self-signed certificate

make-ssl-cert /usr/share/ssl-cert/ssleay.cnf /etc/apache2/ssl/apache.pem

Little problem: by default the certificate is valid only 30 days, you've to edit make-ssl-cert script and add "-days" options, e.g:

openssl req -days 1024 ...

Verify generated certificate

openssl x509 -text -in /etc/apache2/ssl/apache.pem

Start from ssl example config

zcat /usr/share/doc/apache2.2-common/examples/apache2/extra/httpd-ssl.conf.gz \
  > /etc/apache2/sites-available/default-ssl

Activates ssl module

a2enmod ssl

Activates ssl virtualhost

a2ensite default-ssl

Edit /etc/apache2/sites-available/default-ssl

SSLCertificateFile /etc/apache2/ssl/apache.pem
#SSLCertificateKeyFile not required as apache.pem contains also the key

And the usual stuff

DocumentRoot "/var/www"
ServerName ...
ServerAdmin ...
ErrorLog /var/log/apache2/error.log
TransferLog /var/log/apache2/access.log

To activate only the secure ciphers:

SSLCipherSuite HIGH:MEDIUM:!ADH
SSLProtocol -ALL +SSLv3 +TLSv1

Adding Belgian Government Root certificates

You can extract the Belgium Root CA and the Citizen CA from your eID:

pkcs15-tool --read-certificate 04 > /etc/apache2/ssl/ca/belgium.crt
pkcs15-tool --read-certificate 06 >> /etc/apache2/ssl/ca/belgium.crt

Note that with recent cards I had to add the GlobalSign certificate too.
Then add client certificate requirements to /etc/apache2/sites-available/default-ssl

SSLCACertificateFile /etc/apache2/ssl/ca/belgium.crt
SSLOptions +StrictRequire
SSLVerifyClient require
SSLVerifyDepth  10
<Location />
   # accept only certificates emitted by Citizen CA or Foreigner CA:
   SSLRequire %{SSL_CLIENT_I_DN_C} eq "BE" \
   and ( %{SSL_CLIENT_I_DN_CN} in {"Citizen CA"} \
       or %{SSL_CLIENT_I_DN_CN} in {"Foreigner CA"} )
</Location>

According to the doc, because of a bug in Internet Explorer, you also need to add GlobalSign Root certificate...

Xavier Dury proposed to use directly his eID to access a specific directory on an Apache server by "abusing" the Location directive above:
You can add sth like SSLRequire %{SSL_CLIENT_S_DN} but beware of the format of the DN string, it's not the same as with openssl. It should look like "/C=BE/CN=My Name..." and not "C=BE, CN=My Name...".
Moreover special characters must be encoded & protected, e.g. Sébastien has to be coded as S\\xC3\\xA9bastien.

Retrieving citizens' certificate information

The user's distinguish name can be retrieved from php with

$_SERVER['SSL_CLIENT_S_DN']

And the user's name with

$_SERVER['SSL_CLIENT_S_DN_CN']

If those variables are not exported in your environment, check if StdEnvVars is in your Apache SSLOptions for all scripts. On a regular Debian I get:

<FilesMatch "\.(cgi|shtml|phtml|php)$">
    SSLOptions +StdEnvVars
</FilesMatch>
<Directory /usr/lib/cgi-bin>
    SSLOptions +StdEnvVars
</Directory>

TODO: cf apache SSL reverse proxy proposed by the government

Add to /etc/apache2/sites-available/default-ssl:

SSLUseOCSP         on
SSLForceValidation on

Enable ssl_error_module:

LoadModule ssl_error_module modules/mod_ssl_error.so

And add to /etc/apache2/sites-available/default-ssl:

<IfModule mod_ssl_error.c>
SSL_Error_DefaultURL "/error/invalid.html"
SSL_Error_URL  23   "/error/revoked.html"
SSL_Error_URL  10   "/error/expired.html"
</IfModule>

cf doc...

  • Or simply make the client certificate as optional and test for it in php

Hacking phpMyID

Details on the patch

Status:

  • I could validate the client certificate against the root CA and I could extract the data of the certificate
  • I could create various OpenIDs based on the certificate data
    Everything is extracted only from the names and RRN, not on the serial nr of the certificate or any part prone to be changed if you've to renew your ID card! (unless they change the way they write your name on the certificate...)
  • I still consider RRN as sensitive data so the IDs I can provide must be a balance between several factors:
    • friendliness (easy to remember)
    • displaying your name or not?
    • avoid clashes
    • RRN retrieval more or less robust against brute force retrieval
  • So about security & clashes, the hash is very very safe, the others, well, it depends how likely is your name...
  • I added a discover mode which tells you what are your OpenIDs given your own eID, you can try here:
http://id.yobi.be/?openid.mode=discover
# This will return in my case:
http://id.yobi.be/?id=ae96fba0cd9515cd
http://id.yobi.be/?id=philippe.teuwen.159
http://id.yobi.be/?id=philippe.yvon.teuwen

Another kind of ID could be

id=firstname.lastname.Hash(RRN|firstname2|initial3|firstname|lastname)

So it tells your name but still hides RRN is a moderately hard to brute-force hash as you've to guess RRN but also your second firstname & initial of the third firstname (if you've a single firstname you're out of luck, I've 5 firstnames!)

Estonian counterpart plans to provide simply firstname.lastname and to build an index in case of clashes.
But this requires to have a stateful server and I don't want that, I want anybody to build his own service and the generated OpenIDs will always be the same, only depending on the certificate data, not on "who came first".
Otherwise imagine the mess if the server data gets destroyed!

Todo:

  • CRL & cf TODO patches above
  • Maybe some stateful stuff on the server for minor info: pavatar, microid...
  • Check if server is able to do stateful associations
  • Support also for CAcert client certificates, be our own CA?
  • Clean-up server and delegate URLs
  • Move to php-openid

Security:

  • If someone knows your name and your partial hash he can bruteforce your RRN (and your middle name if the attacker didn't get it) but is RRN a secret anymore? Given any email you signed with your eID is enough to simply extract (and not bruteforce) your RRN...