aboutsummaryrefslogtreecommitdiffstats
path: root/posts
diff options
context:
space:
mode:
authorFran├žois Kooman <fkooman@tuxed.net>2016-06-01 08:54:07 +0200
committerFran├žois Kooman <fkooman@tuxed.net>2016-06-01 08:54:07 +0200
commit13feb3f7680723e9ab9c3a889eeeb5f25cc97490 (patch)
tree2320ba9982640181fd640fbc0e713ddde84342dd /posts
downloadwww.tuxed.net-13feb3f7680723e9ab9c3a889eeeb5f25cc97490.zip
www.tuxed.net-13feb3f7680723e9ab9c3a889eeeb5f25cc97490.tar.gz
www.tuxed.net-13feb3f7680723e9ab9c3a889eeeb5f25cc97490.tar.xz
initial commit
Diffstat (limited to 'posts')
-rw-r--r--posts/apache_php_fpm.md204
-rw-r--r--posts/as_discovery.md74
-rw-r--r--posts/group_communication_platform.md142
-rw-r--r--posts/https.md243
-rw-r--r--posts/indiecert.md265
-rw-r--r--posts/indiecert_nitrokey.md118
-rw-r--r--posts/nm_12_openvpn.md50
-rw-r--r--posts/owncloud_distributions.md73
-rw-r--r--posts/proposed_changes_to_indieauth_protocol.md89
-rw-r--r--posts/wireless_router_vpn.md38
10 files changed, 1296 insertions, 0 deletions
diff --git a/posts/apache_php_fpm.md b/posts/apache_php_fpm.md
new file mode 100644
index 0000000..38fb4ea
--- /dev/null
+++ b/posts/apache_php_fpm.md
@@ -0,0 +1,204 @@
+---
+title: Apache and PHP-FPM
+published: 2015-11-01
+modified: 2015-11-02
+---
+
+There is lots of crappy information out there about deploying PHP with Apache,
+or nginx. It is really hard to distill what is really a safe configuration and
+what works. Combining this with a safe TLS configuration nears the
+impossible.
+
+### PHP-FPM
+
+Configuring PHP-FPM is not that difficult, actually, one could keep the
+defaults and that will work pretty well.
+
+```
+$ sudo dnf -y install php-fpm
+```
+
+I only change the configuration not to use a socket, but listen on TCP
+instead. There are some more tweaks you can perform, but to get it working
+reasonably well that is not needed yet.
+
+```
+$ sudo sed -i "s|listen = /run/php-fpm/www.sock|listen = [::]:9000|" /etc/php-fpm.d/www.conf
+$ sudo sed -i "s/listen.allowed_clients = 127.0.0.1/listen.allowed_clients = 127.0.0.1,::1/" /etc/php-fpm.d/www.conf
+```
+
+You possibly have to update the `listen.allowed_clients` if you use a
+separate VM or container for the web server.
+
+Do not forget to enable and start PHP-FPM.
+
+```
+$ sudo systemctl enable php-fpm
+$ sudo systemctl start php-fpm
+```
+
+That should be all for PHP-FPM.
+
+### Apache
+
+We start simple, with a HTTP server serving a PHP application using PHP-FPM.
+
+```
+<VirtualHost www.example.org:80>
+ ServerName www.example.org
+
+ ErrorLog logs/www.example.org_error_log
+ TransferLog logs/www.example.org_access_log
+ CustomLog logs/www.example.org_combined_log combined
+ LogLevel warn
+
+ DocumentRoot /usr/share/my-php-app/web
+
+ <Directory "/usr/share/my-php-app/web">
+ Options -MultiViews
+
+ #Require local
+ Require all granted
+
+ AllowOverride none
+ </Directory>
+
+ # Pass through the "Authorization" header
+ SetEnvIfNoCase ^Authorization$ "(.+)" HTTP_AUTHORIZATION=$1
+
+ # Some request are handled by Apache directly
+ ProxyPass "/css/" !
+ ProxyPass "/img/" !
+ ProxyPass "/js/" !
+ ProxyPassMatch "^/robots.txt$" !
+ ProxyPassMatch "^/favicon.ico$" !
+
+ # The rest goes to PHP-FPM...
+ ProxyPass "/" fcgi://[::1]:9000/usr/share/php-my-app/web/index.php/
+</VirtualHost>
+```
+
+### Apache TLS
+Basically, this means that we remove the current contents of the
+`VirtualHost` block and use it to rewrite to HTTPS instead and move
+the PHP-FPM stuff to the new TLS `VirtualHost`.
+
+```
+<VirtualHost www.example.org:80>
+ ServerName www.example.org
+
+ ErrorLog logs/www.example.org_error_log
+ TransferLog logs/www.example.org_access_log
+ CustomLog logs/www.example.org_combined_log combined
+ LogLevel warn
+
+ RewriteEngine On
+ RewriteCond %{HTTPS} !=on
+ RewriteCond %{ENV:HTTPS} !=on
+ RewriteRule .* https://%{SERVER_NAME}%{REQUEST_URI} [R=301,L]
+</VirtualHost>
+```
+Now, we create a new TLS `VirtualHost` that contains the stuff from
+the previous section and some extra TLS configuration options.
+
+```
+<VirtualHost www.example.org:443>
+ ServerName www.example.org
+
+ ErrorLog logs/www.example.org_ssl_error_log
+ TransferLog logs/www.example.org_ssl_access_log
+ CustomLog logs/www.example.org_ssl_combined_log combined
+ LogLevel warn
+
+ DocumentRoot /usr/share/php-my-app/web
+
+ SSLEngine on
+ SSLCertificateFile /etc/pki/tls/certs/www.example.org.crt
+ #SSLCertificateChainFile /etc/pki/tls/certs/www.example.org-chain.crt
+ SSLCertificateKeyFile /etc/pki/tls/private/www.example.org.key
+
+ SSLProtocol all -SSLv3 -TLSv1
+ SSLCipherSuite 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:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK
+ SSLHonorCipherOrder on
+ SSLCompression off
+
+ # OCSP Stapling, only in httpd 2.3.3 and later
+ SSLUseStapling on
+ SSLStaplingResponderTimeout 5
+ SSLStaplingReturnResponderErrors off
+
+ # HSTS (mod_headers is required) (15768000 seconds = 6 months)
+ Header always set Strict-Transport-Security "max-age=15768000"
+
+ <Directory "/usr/share/php-my-app/web">
+ Options -MultiViews
+
+ Require all granted
+ AllowOverride none
+ </Directory>
+
+ # Pass through the "Authorization" header
+ SetEnvIfNoCase ^Authorization$ "(.+)" HTTP_AUTHORIZATION=$1
+
+ # Some request are handled by Apache directly
+ ProxyPass "/css/" !
+ ProxyPass "/img/" !
+ ProxyPass "/js/" !
+ ProxyPassMatch "^/robots.txt$" !
+ ProxyPassMatch "^/favicon.ico$" !
+
+ # The rest goes to PHP-FPM...
+ ProxyPass "/" fcgi://[::1]:9000/usr/share/php-my-app/web/index.php/
+</VirtualHost>
+```
+
+Now we still need to generate the key and certificate and optionally have them
+signed by some CA. The following commands make this very easy:
+
+```
+# Generate the private key
+$ sudo openssl genrsa -out /etc/pki/tls/private/www.example.org.key 2048
+$ sudo chmod 600 /etc/pki/tls/private/www.example.org.key
+
+# Create the CSR (optionally, send this to CA to have signed)
+$ sudo openssl req -subj "/CN=www.example.org" -sha256 -new -key /etc/pki/tls/private/www.example.org.key -out www.example.org.csr
+
+# Create the (self signed) certificate and install it
+$ sudo openssl req -subj "/CN=www.example.org" -sha256 -new -x509 -key /etc/pki/tls/private/www.example.org.key -out /etc/pki/tls/certs/www.example.org.crt
+```
+
+If you want to have the certificate signed by a CA, use the CSR generated
+above and send it to the CA. Once you get a certificate back, overwrite the
+self signed certificate in `/etc/pki/tls/certs/www.example.org.crt`
+and make sure to also configure the `SSLCertificateChainFile`.
+
+Next you can just place the two `VirtualHost` sections above in one
+file, put it in `/etc/httpd/conf.d/www.example.org.conf` and enable
+and start Apache.
+
+```
+$ sudo systemctl enable httpd
+$ sudo systemctl start httpd
+```
+
+### Unanswered Questions
+
+This stuff is so complex that there are still some issues that I do not know
+how to solve. Hopefully this list will become smaller over time.
+
+- The URL passed to PHP-FPM is still "URL encoded", for example `%20` is not
+ converted back to `SPACE`;
+- Should we actually have the `RewriteCond` rules in the HTTP `VirtualHost`
+ section? It MUST always be rewritten?
+
+### Resources
+
+These resources are a MUST. Make sure to take note of everything that is
+mentioned there! Do not trust what I write here without thinking for yourself
+and making sure you understand everything.
+
+- [PHP: The Right Way](http://www.phptherightway.com/#servers_and_deployment) (Servers and Deployment)
+- [Mozilla SSL Configuration Generator](https://mozilla.github.io/server-side-tls/ssl-config-generator/)
+- [SSL Server Test](https://www.ssllabs.com/ssltest/) (Qualys)
+- [SSL Decoder](https://ssldecoder.org/) (Remy van Elst)
+- [Earlier blog post on HTTPS](https.html)
diff --git a/posts/as_discovery.md b/posts/as_discovery.md
new file mode 100644
index 0000000..547455c
--- /dev/null
+++ b/posts/as_discovery.md
@@ -0,0 +1,74 @@
+---
+title: OAuth 2.0 Authorization Server Discovery
+published: 2015-07-31
+---
+
+### Introduction
+
+Currently an OAuth client is supposed to know the Authorization Server (AS)
+that is used by a particular Resource Server (RS). This blog post proposes a
+discovery mechanism where the client only needs to know the location of the RS.
+
+The RS chooses the AS it will use. There is no point for the client to know
+what the AS is beforehand. It can also change at any point at the
+RS's discretion. As far as I know there is no standardized way of doing this.
+
+### Proposal
+
+Currently, the `WWW-Authenticate` header is sent back by the RS
+if no `Authorization` header is provided by the client or if it uses
+an invalid or expired token. If the client sends an "unauthenticated" request,
+i.e. without the `Authorization` header, like shown below:
+
+```
+POST /endpoint HTTP/1.1
+Host: rs.example.org
+Content-Type: application/x-www-form-urlencoded
+
+foo=bar
+```
+
+In most cases this will not succeed, although in some it might if out-of-band
+authorization was already establish, e.g. using Kerberos in enterprise
+networks. However, in most scenarios this request will not be allowed.
+Currently the response would be like this:
+
+```
+HTTP/1.1 401 Unauthorized
+WWW-Authenticate: Bearer
+ realm="Phubble"
+```
+
+Now, the OAuth Bearer specification provides for specifying the OAuth scope
+required for performing a certain action, e.g. the scope
+`https://micropub.net/scope#create` is required to be able to
+perform the operation. This field is then included in the
+`WWW-Authenticate` header to tell the client which scope to
+request:
+
+```
+HTTP/1.1 401 Unauthorized
+WWW-Authenticate: Bearer
+ realm="Phubble",
+ scope="https://micropub.net/scope#create"
+```
+
+Now, for discovery of the AS I propose two new key-value pairs:
+`authorization_endpoint` and `token_endpoint`. This will
+allow the client to select the correct AS:
+
+```
+HTTP/1.1 401 Unauthorized
+WWW-Authenticate: Bearer
+ realm="Phubble",
+ scope="https://micropub.net/scope#create",
+ authorization_endpoint="https://as.example.org/authorize",
+ token_endpoint="https://as.example.org/token"
+```
+
+This proposal thus solves two issues: the discovery of the AS and the discovery
+of the required scope for a particular action on the RS's endpoint.
+
+### References
+
+- [RFC 6750 "The OAuth 2.0 Authorization Framework: Bearer Token Usage](https://tools.ietf.org/html/rfc6750)
diff --git a/posts/group_communication_platform.md b/posts/group_communication_platform.md
new file mode 100644
index 0000000..c81c159
--- /dev/null
+++ b/posts/group_communication_platform.md
@@ -0,0 +1,142 @@
+---
+title: Group Communication Platform
+published: 2015-08-11
+modified: 2015-08-12
+---
+
+**Update (2015-08-12)**: see
+[private-messaging-brainstorming](https://indiewebcamp.com/private-messaging-brainstorming)
+for a discussion on the topic of private messaging. It is in a way quite similar to
+the proposal below of "Inbox", but without OAuth.
+
+### Introduction
+
+This post will describe some typical features for a group communication
+platform with code name *Phubble*. As an example we will organize a
+birthday party for Alice. This post will describe what would be required of
+a "platform" to make it work for the IndieWeb.
+
+### Alice's birthday party
+
+Alice has a birthday in the near future. Bob, Eve and Mallory want to create a
+surprise party for Alice. Until now they used "Facebook Groups" to organize
+such an event among the friends.
+
+Bob wants to coordinate the party with Eve and Mallory and have a secure way
+of communicating among themselves without Alice, or anyone else finding out
+about it.
+
+The group of friends contains three members:
+
+- `https://bob.example/`
+- `https://eve.example/`
+- `https://mallory.example/`
+
+Bob creates a private space `alice-bday-party` on
+*Phubble* and assigns the members to it.
+
+*Phubble* will now have to figure out how to contact/notify the members
+by some mechanism to notify them they have been added to the private group.
+For example using an HTTP *inbox* or maybe email if an HTTP
+*inbox* is not listed on the member's homepage.
+
+Bob then posts his first idea to the wall. Eve and Mallory will receive a
+another notification saying that Bob posted a new message, possibly with the
+content of the message included, or maybe just a link.
+
+Eve wants to add Peggy to the group. She adds her to the group configured in
+*Phubble* with the identity `https://peggy.example/`. It
+should be possible for all members of a space to add new members. Only the
+creator can delete members.
+
+*Phubble* sends Peggy a notification that she was added to the
+`alice-bday-party` space, and will also inform her of any future
+activity.
+
+Peggy also has an idea and posts it to the space. Now Bob, Eve and Mallory will
+get a notification.
+
+### Notifications
+
+In order to notify a member (out of the blue) that he or she is a member of a
+(private) group space there needs to be a mechanism for doing this. Email has
+long been the most reliable way to do this. Most users will publish their
+email address on their homepage, for example using the
+[h-card](https://en.wikipedia.org/wiki/HCard) microformat as
+promoted for the IndieWeb or the
+[rel="me"](http://microformats.org/wiki/relme) method. In
+addition below a mechanism using HTTP is proposed, HTTP *inbox*.
+
+#### HTTP *inbox*
+
+The user advertises a HTTP *inbox* on their homepage:
+
+```
+ <link rel="inbox" href="https://tuxed.net/inbox">
+```
+
+This endpoint accepts a HTTP POST containing a subject and a message:
+
+```
+POST /inbox HTTP/1.1
+Host: tuxed.net
+Content-Type: application/x-www-form-urlencoded
+
+subject=New+message+in+%22Alice%27s+birthday%22+space&content=Lorem+ipsum+dolor+sit.
+```
+
+This request needs an OAuth 2.0 Bearer token to succeed. If non provided, the
+`inbox` endpoint will respond with some hints, as proposed by
+[OAuth 2.0 Authorization Server Discovery](as_discovery.html).
+
+```
+HTTP/1.1 401 Unauthorized
+WWW-Authenticate: Bearer
+ realm="Inbox",
+ authorization_endpoint="https://as.example.org/authorize",
+ token_endpoint="https://as.example.org/token"
+```
+
+Now *Phubble*, as an OAuth client, knows where to obtain authorization.
+*Phubble* chooses its own "authorization server", e.g. one that supports
+client certificates, and uses its own URL, e.g.
+`https://phubble.example/` as its identity. Assuming the AS supports
+[Distributed IndieAuth](https://indiewebcamp.com/distributed-indieauth)
+this should work perfectly well.
+
+Once the access token has been obtained it can be sent in the POST request:
+
+```
+POST /inbox HTTP/1.1
+Host: tuxed.net
+Authorization: Bearer SFmrZYeCR9hCol2ORAusJbccHiHrp7MU
+Content-Type: application/x-www-form-urlencoded
+
+subject=New+message+in+%22Alice%27s+birthday%22+space&content=Lorem+ipsum+dolor+sit.
+```
+
+Now the response will show it succeeded:
+
+```
+ HTTP/1.1 201 Created
+```
+
+#### Email
+
+Email is a safe fallback. The user's email address can be discovered from the
+homepage, for example by querying the `rel="me"` `link`
+headers:
+
+```
+ <link rel="me" href="mailto:fkooman@tuxed.net">
+```
+
+This will be all that is needed to send notifications.
+
+### Issues
+
+- How does *Phubble* keep track of new users in the ACL that need to be
+notified that they are now member of the space?
+- How do we deal with disabling notifications? Opt-in? Opt-out?
+- Should we implement a distinction between "invited" and "member"? So only
+when people accept a membership they will start receiving notifications?
diff --git a/posts/https.md b/posts/https.md
new file mode 100644
index 0000000..a2db107
--- /dev/null
+++ b/posts/https.md
@@ -0,0 +1,243 @@
+---
+title: HTTPS
+published: 2015-07-21
+modified: 2015-07-21
+---
+
+**Update** (2015-07-21): fix the link to the Apache configuration file.
+
+This document will not explain why to use HTTPS for your site, but assume you
+are already convinced :-)
+
+### Certificate Authority
+
+So if you want to do HTTPS everyone focuses only on the certificate and the
+costs, but the costs seem to be going down or reach zero in some cases,
+although that can be treacherous in some cases, like StartSSL. Personally
+I've used [https://namecheap.com](https://namecheap.com), because at
+the time they were one of the cheaper ones that supported SHA-256 for signing
+the certificates. I do not recommend to use
+[StartSSL](https://startssl.com) because they have a ridiculous
+policy regarding revoking certificates. You have to pay to revoke. This is SO
+bad, and considering you may require revocation at some point because someone
+compromised your server... not a great prospect. You can also use [CAcert](http://cacert.org) (not recommended), or wait for [Let's Encrypt](https://letsencrypt.org/).
+
+
+### Generating the signing request
+
+Many tutorials only tell you to do the wrong thing. Either they are old, or
+obsolete or do crazy things. It is important to generate the private key on a
+physical device, e.g. your laptop, as virtual machines potentially have bad
+random due to the lack of entropy.
+
+Below is the procedure I used for [IndieCert](https://indiecert.net).
+To generate the private key:
+
+```
+$ openssl genrsa -out indiecert.net.key 2048
+```
+
+Create a file `indiecert.net.cnf` containing the following:
+
+```
+[req]
+prompt = no
+distinguished_name = distinguished_name
+
+[distinguished_name]
+CN = www.indiecert.net
+
+[v3_req]
+subjectAltName = DNS:www.indiecert.net, DNS:indiecert.net
+```
+
+Now generate the CSR:
+
+```
+$ openssl req -sha256 -new -reqexts v3_req -config indiecert.net.cnf -key indiecert.net.key -out indiecert.net.csr
+```
+
+Because OpenSSL (and the config) is so tricky to get right, also here the output
+of the CSR in "human readable" form:
+
+```
+$ openssl req -in indiecert.net.csr -noout -text
+Certificate Request:
+ Data:
+ Version: 0 (0x0)
+ Subject: CN=www.indiecert.net
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: <strong>(2048 bit)</strong>
+ Modulus:
+ 00:b8:fa:6b:12:e8:50:c8:22:db:ea:2e:1a:99:dc:
+ 8d:45:ff:89:ac:c8:1d:6d:02:25:ff:17:fa:4b:67:
+ 00:28:39:16:82:12:e1:82:52:ae:06:1b:2a:6f:2f:
+ af:bd:a5:41:46:91:86:81:67:02:50:fc:f8:44:a7:
+ 67:66:e2:69:48:08:e1:25:8a:2d:c0:b1:8e:b7:05:
+ f3:7f:ab:68:0e:46:41:5a:f3:e2:dd:c8:60:70:c4:
+ 9a:4b:e7:34:1b:8c:07:5d:da:72:42:1a:ee:8e:4b:
+ ce:ec:da:6e:3e:b7:b2:b9:d2:41:78:09:ad:4d:3a:
+ 8a:ab:51:ec:32:9d:7b:ba:c5:3d:81:c4:11:78:8c:
+ e4:04:ef:67:24:88:f2:28:33:c8:71:1c:e2:c6:f2:
+ 38:2e:57:6c:94:6f:f8:a9:fd:4d:4a:67:29:d9:2e:
+ 3c:7e:11:1a:cf:39:d2:e2:89:11:38:6a:09:10:36:
+ 8c:93:04:28:79:f7:a7:f4:5c:8f:f3:2e:2c:0a:a5:
+ 90:74:cb:63:4a:c8:d9:d2:1d:ab:4b:6a:1e:eb:f1:
+ 8e:85:f4:5b:90:1c:51:d5:df:b1:82:6c:b2:a6:d0:
+ 7e:01:0b:44:ec:96:3e:2d:0f:6e:87:21:2d:70:26:
+ b6:3a:f5:81:e4:a8:2d:b4:ca:8a:d3:29:ad:0f:c3:
+ 9d:49
+ Exponent: 65537 (0x10001)
+ Attributes:
+ Requested Extensions:
+ X509v3 Subject Alternative Name:
+ DNS:www.indiecert.net, DNS:indiecert.net
+ Signature Algorithm: <strong>sha256WithRSAEncryption</strong>
+ 52:f7:9d:14:b4:43:de:52:0b:6f:aa:ff:7a:32:cf:ca:5e:6c:
+ 09:94:32:02:77:8c:ed:03:07:6e:e6:d4:a8:12:74:21:fb:bc:
+ a8:e5:ac:c4:af:6a:df:86:c0:05:07:3c:9e:53:de:ab:bb:37:
+ 55:2a:f3:f8:1d:fe:6e:92:21:44:bb:3e:c4:a9:fe:a4:4d:f4:
+ 68:1d:6b:fe:59:ea:95:d6:4f:2b:9f:cc:f9:0d:a2:7e:e0:96:
+ 8d:32:8b:1c:39:d4:b6:b2:6e:70:98:b2:c1:da:df:5f:72:e2:
+ 50:0a:54:08:05:f7:82:23:8f:89:4f:94:c4:0c:a1:7b:33:cc:
+ ed:0f:5d:87:ed:98:64:e7:b2:ef:1f:12:08:6c:8a:6e:dc:d2:
+ 85:f9:77:ec:77:ce:53:63:a7:21:37:21:53:51:cb:7e:a8:d3:
+ a5:e6:43:e2:96:de:10:83:e4:8a:8a:05:1d:5f:65:31:8d:d1:
+ 8c:8d:2f:9e:04:1c:9e:d5:c9:88:40:eb:7d:7d:34:8d:43:37:
+ 71:d9:fd:45:34:4a:b2:c2:80:0f:85:2d:ed:5c:0d:5d:ef:ae:
+ 3b:94:ea:3a:ea:3b:ad:f3:90:46:6e:a6:4a:d6:c7:57:36:3a:
+ c2:71:ef:f7:d8:8d:cc:16:c1:2f:6f:ca:3f:bb:e0:2d:73:bc:
+ 04:59:89:07
+```
+
+It is important to make sure you have at least an 2048 bits public key, and
+that SHA-256 was used for the signature. This will in most cases trigger the
+CA to also use SHA-256 if they still support SHA-1 as well.
+
+Most CAs will override the CN and the Subject Alternative Name in most cases,
+but it doesn't hurt to get it right yourself :-)
+
+## CA procedure
+
+The CA will now take this CSR and sign it and send you a signed certificate and
+also in most cases a certificate chain:
+
+```
+$ openssl x509 -inform PEM -in www_indiecert_net.crt -noout -text
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ f1:ce:c2:0e:e7:b4:2f:d8:c4:a5:78:c5:e9:f5:4b:07
+ Signature Algorithm: <strong>sha256WithRSAEncryption</strong>
+ Issuer: C=GB, ST=Greater Manchester, L=Salford, O=COMODO CA Limited, CN=COMODO RSA Domain Validation Secure Server CA
+ Validity
+ Not Before: Feb 18 00:00:00 2015 GMT
+ Not After : Feb 18 23:59:59 2016 GMT
+ Subject: <strong>OU=Domain Control Validated, OU=PositiveSSL, CN=www.indiecert.net</strong>
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:e1:4c:bd:f2:03:cb:cd:d9:33:b4:56:c4:a3:52:
+ 2d:47:4e:1a:df:5a:8b:9e:75:01:51:29:9a:37:83:
+ 63:d5:44:b4:6d:fa:b2:c1:a4:97:76:44:b1:f3:e6:
+ 96:8f:40:40:85:fe:04:f6:04:65:ae:8d:e1:79:60:
+ 32:eb:21:6f:8b:9c:85:2d:d9:38:aa:ea:7c:50:d0:
+ fd:25:29:a3:16:ef:c5:d1:ae:bc:0f:7d:82:41:8e:
+ cb:df:d2:da:41:4d:fd:2e:4c:4c:7f:32:aa:7a:10:
+ aa:73:99:21:f3:e1:a1:14:7b:5a:ca:f9:69:87:b1:
+ 35:6f:86:56:6a:54:57:1d:8b:fd:1f:7a:56:d3:44:
+ 67:54:99:8d:8c:70:2c:ba:4c:00:ff:6b:a4:0b:bf:
+ 0e:c9:dc:b9:ea:bb:0c:9e:a5:02:b2:c9:34:4e:e2:
+ 34:be:7f:e5:a5:e5:ed:d0:97:7f:6c:c0:aa:a9:b8:
+ 24:76:78:12:49:e5:a5:f8:08:71:3f:55:d4:21:04:
+ 7c:c0:5c:31:20:87:29:5e:a1:bd:b1:7d:63:e9:3f:
+ 0e:f2:a8:fb:1f:d8:e8:51:0f:89:84:dc:5d:da:7a:
+ 69:a5:cd:48:ba:39:63:d8:ae:39:29:cd:a7:8f:94:
+ 06:9a:7f:da:c7:b6:f4:71:a1:58:03:ef:10:b4:22:
+ a1:7f
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Authority Key Identifier:
+ keyid:90:AF:6A:3A:94:5A:0B:D8:90:EA:12:56:73:DF:43:B4:3A:28:DA:E7
+
+ X509v3 Subject Key Identifier:
+ FD:00:76:8D:04:A1:3E:B1:41:2B:49:8A:D1:CD:93:89:32:3C:38:B5
+ X509v3 Key Usage: critical
+ Digital Signature, Key Encipherment
+ X509v3 Basic Constraints: critical
+ CA:FALSE
+ X509v3 Extended Key Usage:
+ TLS Web Server Authentication, TLS Web Client Authentication
+ X509v3 Certificate Policies:
+ Policy: 1.3.6.1.4.1.6449.1.2.2.7
+ CPS: https://secure.comodo.com/CPS
+ Policy: 2.23.140.1.2.1
+
+ X509v3 CRL Distribution Points:
+
+ Full Name:
+ URI:http://crl.comodoca.com/COMODORSADomainValidationSecureServerCA.crl
+
+ Authority Information Access:
+ CA Issuers - URI:http://crt.comodoca.com/COMODORSADomainValidationSecureServerCA.crt
+ OCSP - URI:http://ocsp.comodoca.com
+
+ X509v3 Subject Alternative Name:
+ <strong>DNS:www.indiecert.net, DNS:indiecert.net</strong>
+ Signature Algorithm: <strong>sha256WithRSAEncryption</strong>
+ 69:c1:22:36:c1:2b:5d:43:34:c0:d7:a6:06:03:53:02:f4:85:
+ ee:29:72:c2:82:37:56:af:ba:f8:1e:c9:2c:bf:da:fb:38:47:
+ 43:8d:c1:d3:94:48:b3:49:41:1c:f5:89:7c:97:23:88:0a:b3:
+ cb:47:28:13:a2:a7:d2:d2:3c:40:5b:1b:8b:98:ae:70:4c:ea:
+ 67:77:e1:b8:d4:de:c7:0e:fd:09:ff:56:72:a8:30:eb:0d:0a:
+ 87:fe:2c:3f:9d:2e:7a:e3:de:47:22:79:dd:2a:58:da:38:78:
+ 14:2b:70:95:ee:8b:ce:9c:78:b0:ce:a7:cb:27:dd:98:36:f8:
+ b4:f8:4c:44:35:b9:9d:d4:8c:cc:5b:c6:48:6e:25:12:e3:ce:
+ 9e:40:c7:c4:b9:d1:23:6b:93:83:e2:4e:29:7e:10:1a:31:72:
+ d0:a0:24:97:3d:ea:b1:89:27:0b:49:0c:33:c7:ff:f2:e9:cb:
+ 4b:fe:a7:0a:10:c3:11:65:dc:f0:4a:07:32:63:d4:73:d5:30:
+ 77:9d:f4:fc:d3:51:04:11:51:af:8d:f6:37:d1:de:61:3c:74:
+ 5d:6a:64:f0:c6:99:45:21:1e:44:1c:01:61:99:3e:c1:a7:e4:
+ a0:d1:39:f0:56:33:e6:7b:db:6d:22:73:c4:7f:d0:22:2e:54:
+ 93:0e:59:e4
+```
+
+### Installation
+
+Now you can use the certificate, the key and the certificate chain and
+configure them in your web server. If you run your own server you SHOULD use
+Mozilla's [configuration generator](https://mozilla.github.io/server-side-tls/ssl-config-generator/) to make sure you configure your server in a secure way.
+
+If you use some virtual hosting provider, like e.g. [Uberspace.de](https://uberspace.de) you can probably upload your key, certificate and chain using SSH and instruct them to configure the certificate for you.
+
+### Validation
+
+This is where most people stop. They will never validate their configuration
+and make sure SSLv3 is disabled, the chain is configured properly or the
+weak ciphers are disabled.
+
+Go to [SSL Server Test](https://www.ssllabs.com/ssltest/) provided
+by Qualys. Enter your domain name and check the results. If you do not
+get a rating A or A+ you are doing something wrong and should evaluate the
+results of the test. As an example, you can view the IndieCert [report](https://www.ssllabs.com/ssltest/analyze.html?d=indiecert.net&hideResults=on).
+
+If you prefer a free software solution you can also look at [SSL Decoder](https://tls.so/). But it is advisable to also check using the Qualys tool mentioned above.
+
+### Next Steps
+
+Now that the basics are done, you should not stop here, but consider a few
+other things:
+
+- [HTTP Strict Transport Security](https://developer.mozilla.org/en-US/docs/Web/Security/HTTP_strict_transport_security)
+- [OCSP Stapling](https://wiki.mozilla.org/Security/Server_Side_TLS#OCSP_Stapling)
+- [Add to HSTS preload list](https://hstspreload.appspot.com/)
+- [Public Key Pinning](https://developer.mozilla.org/en-US/docs/Web/Security/Public_Key_Pinning)
+
+### What did I do so far?
+
+For IndieCert I followed most of these steps, but didn't get around to
+implementing Public Key Pinning yet. You can check the Apache configuration I
+use [here](https://github.com/fkooman/indiecert/blob/master/docker/indiecert.example-httpd.conf).
diff --git a/posts/indiecert.md b/posts/indiecert.md
new file mode 100644
index 0000000..8f5fedc
--- /dev/null
+++ b/posts/indiecert.md
@@ -0,0 +1,265 @@
+---
+title: Introducing IndieCert
+published: 2015-02-02
+modified: 2015-03-08
+---
+
+**More feedback is required before this document can be considered finished. See "Issues" section below.**
+
+Authenticating to web servers with a client certificate, installed in the
+user's browser, is unfortunately not widely used. They are convenient and safe
+to use once the initial hurdle of installing them is taken.
+
+There is now a Proof of Concept instance! Check it out [here](https://indiecert.net)!
+
+The main benefit is easy and secure authentication. There is no need to provide
+a password to any service, only the URL to your home page. So there is no
+chance you will leak your password to some service.
+
+<video controls="controls" width="575">
+ <source src="https://storage.tuxed.net/fkooman/public/upload/blog/indiecert_auth_flow.webm" type="video/webm">
+ <source src="https://storage.tuxed.net/fkooman/public/upload/blog/indiecert_auth_flow.mp4" type="video/mp4">
+</video>
+
+In addition, this proposal describes a way to make the use of client certificates
+feasible:
+
+1. A self-signed CA is used instead of a 'browser trusted' CA to issue the client certificates, this works without browser warnings;
+2. Users authorize the certificates by publishing the certificate fingerprint on their home page allowing to claim ownership of a URL and by authenticating with the certificate directly;
+3. Allow identity (certificate) linking using the user's home page address to allow registration of multiple fingerprints to support multiple devices and browsers.
+
+A possible drawback is that many users do not have a home page anymore. They
+have a Facebook profile or a Twitter account, but no home page. However, this
+is not relevant for [IndieWeb](https://indiewebcamp.com/) as all
+users should have their own home page running on their own domain anyway :)
+
+As a fallback it is possible to allow authenticating using existing social
+networks, similar to [IndieAuth](https://indieauth.com), instead
+of using the client certificates. Some browsers and operating systems
+unfortunately do not support easy client certificate enrollment.
+
+<img src="https://storage.tuxed.net/fkooman/public/upload/blog/keep-calm-and-use-certificates.png" width="300" height="350" alt="keep calm and use certificates">
+
+### Protocol for Relying Parties
+
+The protocol follows the protocol proposed for IndieAuth. The protocol is
+based on the IndieAuth protocol and aims to be compatible with it.
+
+#### Request Authentication
+
+The service redirects the user to `https://indiecert.net/auth` to
+start the authentication phase. Two parameters need to be specified:
+
+- **redirect_uri**:
+ - the URL the browser should be redirected back to after the authentication is successful. This MUST be a valid HTTPS URL;
+- **me**:
+ - the URL to the user's home page (see [Retrieving the User's Home Page](#retrieve_home_page));
+
+##### Example
+Below is an example of a browser redirect. The process can also be initiated
+with a `<form>` submit using the `GET` method.
+
+```
+HTTP/1.1 302 Found
+Location: https://indiecert.net/auth?redirect_uri=https://example.org/callback&amp;me=https://tuxed.net/fkooman
+```
+
+IndieCert will at this point take care of the authentication and optional
+enrollment process if that was not already done.
+
+#### Authentication Response
+
+IndieCert will redirect the browser back to the `redirect_uri`
+specified in the authentication request after the user is authenticated at
+IndieCert.
+
+##### Example
+
+```
+HTTP/1.1 302 Found
+Location: https://example.org/callback?code=wW3OLXJZn35d7zFwg9YGmWti
+```
+
+#### Verification Request
+
+The `code` parameter can now be used to request the claimed user
+identity. The following parameters are required:
+
+<dl>
+ <dt>`code`</dt>
+ <dd>the code obtained in the authentication response query parameter `code`.</dd>
+ <dt>`redirect_uri`</dt>
+ <dd>the URL the browser was redirected back to after the successful authentication;</dd>
+</dl>
+
+Now a HTTP `POST` can be used to obtain the user's (normalized) home
+page URL:
+
+```
+POST /auth HTTP/1.1
+Host: indiecert.net
+Content-Type: application/x-www-form-urlencoded
+Accept: application/json
+
+redirect_uri=https%3A%2F%2Fexample.org%2Fcallback&amp;code=wW3OLXJZn35d7zFwg9YGmWti
+```
+
+The response will be formatted as JSON indicating the actual user home page in
+the `me` parameter.
+
+This is the identity that MUST be used by the relying party to identify the
+user as it could differ from the initial `me` specified by the user,
+e.g.: redirects were followed to reach the user's home page.
+
+```
+HTTP/1.1 200 OK
+Content-Type: application/json
+Cache-Control: no-store
+Pragma: no-cache
+
+{
+ "me": "https://www.tuxed.net/fkooman/"
+}
+```
+
+In case there was a failure in verifying the code, e.g. it was already used, or
+not valid the following response can be expected:
+
+
+```
+HTTP/1.1 400 Bad Request
+Content-Type: application/json
+Cache-Control: no-store
+Pragma: no-cache
+
+{
+ "error":"invalid_request"
+}
+```
+
+### Protocol for the IndieCert Service
+
+The IndieCert service has to deal with certificates, issuing, installing and
+verifying them. The most convenient method is to use the HTML
+`<keygen>` tag. This makes the browser generate a private key
+and certificate request (SPKAC) that is then sent to the service for signing.
+The service will sign this with the CA generated for this particular IndieCert
+instance. The signed certificate is sent back to the client and (automatically)
+imported in the browser certificate store.
+
+After this, the certificate can be used to authenticate to the IndieCert
+service, but it still needs to be linked to the URL of the user's home page.
+This can be done by using the `rel="me"` attribute in a
+`<link>` header tag or `<a>` body tag.
+
+```
+<link rel="me" href="ni://indiecert.net/sha-256;WXXyBZDo1pZYiLbrCNGFtSdSamqEvSJJBRzpx-MNIUA?ct=application/x-x509-user-cert">
+```
+
+Once the user has placed this HTML element on their home page the URL it will
+be found when the IndieCert instance will fetch the URL and extract all
+`<link>` and `<a>` tags to look for the
+`rel="me"` attribute. The fingerprint of the client certificate
+used to authenticate to IndieCert needs to be listed on the home page.
+After that, the URL of the home page will be used as an accepted identifier.
+
+<video controls="controls" width="575">
+ <source src="https://storage.tuxed.net/fkooman/public/upload/blog/indiecert_enroll.webm" type="video/webm">
+ <source src="https://storage.tuxed.net/fkooman/public/upload/blog/indiecert_enroll.mp4" type="video/mp4">
+</video>
+
+#### Retrieving the User's Home Page
+
+The user's home page MUST be fetched over HTTPS only, MUST follow redirects and
+MUST NOT have any HTTP URLs in its redirect path. If the URL does not start
+with `https://` it MUST be added by IndieCert. If a URL starts with
+`http://` or is otherwise invalid it MUST be rejected. The final
+URL, the URL that returns a `200 OK` status, MUST be used in the
+response to the verification request, this is the normalized home page URL.
+
+For example the user provides `tuxed.net/fkooman`. IndieCert makes
+this `https://tuxed.net/fkooman` and starts the fetching process. It
+is then redirected to `https://www.tuxed.net/fkooman` and then to
+`https://www.tuxed.net/fkooman/`. The claimed identity thus becomes
+`https://www.tuxed.net/fkooman/` and this value is returned in
+response to the verification request.
+
+### Identity Linking
+
+One of the benefits of publishing fingerprints on the user's home page is that
+additional client certificate fingerprints can easily be added to the home page
+to allow those certificates to claim the same identity.
+
+```
+<!-- laptop -->
+<link rel="me" href="ni://indiecert.net/sha-256;WXXyBZDo1pZYiLbrCNGFtSdSamqEvSJJBRzpx-MNIUA?ct=application/x-x509-user-cert">
+
+<!-- phone -->
+<link rel="me" href="ni://indiecert.net/sha-256;ThIaJ7TJQ1oAIKCGKe0BdBO3Bh8NzxZeyAa-WCTuzpU?ct=application/x-x509-user-cert">
+```
+
+Certificate revocation is done by removing the entry from the home page and it
+can no longer be used to claim the identity.
+
+### Fingerprint Generation
+
+The fingerprint of the certificate is generated by calculating the SHA-256 hash
+over the DER encoded certificate and base64url encoding the resulting binary
+string according to RFC 6920 "Naming Things with Hashes" and RFC 4648
+"The Base16, Base32, and Base64 Data Encodings". An example of calculating a
+fingerprint in PHP:
+
+```
+<?php
+$string = 'Hello World!';
+echo rtrim(strtr(base64_encode(hash('SHA256', $string, true)), '+/', '-_'),'=');
+```
+
+### Distributed IndieCert
+
+One of the important issues to solve is how to make this protocol distributed,
+i.e.: how to allow multiple instances of IndieCert to be used by different
+services whilst allowing a smooth user experience.
+
+The relying party can choose to join an existing IndieCert instance, or run
+their own if they don't trust any of the existing instances. The benefit of
+running their own is better control and more trust and no requirement on third
+parties for the authentication to their service.
+
+Assuming they want to run their own instance that would require the user to
+generate a new certificate and put the fingerprint on their home page as well.
+This results in additional overhead, for the user, but may be worth it from a
+security perspective. And the process needs to be repeated once per IndieCert
+instance, per device or even per browser. This the greatest weakness of this
+proposal, that and adoption. If everyone runs their own IndieCert instance it
+will quickly become a management nightmare for the user if they have to keep
+track of all certificates in all their browsers on all their devices. This
+could be solved by a tool allowing users to easily add fingerprints to their
+website.
+
+For the actual user experience, the user just selects the specific certificate
+for the specific IndieCert instance (it can be pre-selected by most browsers
+based on the CA) so that should not be a problem.
+
+### Issues
+
+There are a number of issues we have to solve before this document can be
+considered stable:
+
+- CSRF. User X can generate a code for his identity and trick user Y into
+ going to a relying party with user X's code to work under user X's identity,
+ possibly storing private data under user X's identity instead of user Y's. We
+ need to implement some kind of state generating/checking;
+- Rate limiting on the verify endpoint;
+- Many browsers, many devices, many instances of IndieCert is a scalability nightmare for the user...
+
+### References
+
+- [IndieAuth](https://indieauth.com)
+- [IndieWebCamp](https://indiewebcamp.com)
+- [RelMeAuth](http://microformats.org/wiki/RelMeAuth)
+- [Certificate Download Specification](https://wiki.mozilla.org/CA:Certificate_Download_Specification)
+- [Keygen Tag](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/keygen)
+- [Naming Things with Hashes](http://tools.ietf.org/html/rfc6920) (RFC 6920)
+- [The Base16, Base32, and Base64 Data Encodings](http://tools.ietf.org/html/rfc4648) (RFC 4648)
+- [The OAuth 2.0 Authorization Framework](https://tools.ietf.org/html/rfc6749) (RFC 6749)
diff --git a/posts/indiecert_nitrokey.md b/posts/indiecert_nitrokey.md
new file mode 100644
index 0000000..95fafb7
--- /dev/null
+++ b/posts/indiecert_nitrokey.md
@@ -0,0 +1,118 @@
+---
+title: IndieCert and Nitrokey
+published: 2015-04-07
+---
+
+Finally I managed to get het Nitrokey working with IndieCert. It is not as
+smooth as expected and requires a fair bit of work, but here you can find the
+steps required.
+
+### Requirements
+
+The documentation for Nitrokey seems scattered or lacking a bit. Below I will
+describe what to do on the latest [Fedora](https://getfedora.org)
+(21) release.
+
+#### PCSC
+
+You need to install two packages to get started and recognize the Nitrokey:
+
+```
+$ sudo yum -y install opensc.x86_64 pcsc-lite.x86_64
+```
+
+Now you can make the PCSC daemon start on system boot
+
+```
+$ sudo systemctl enable pcscd.service
+```
+
+`pcscd` is *socket activated*, so no need to start it, it
+will be activated when you plug in the Nitrokey. If you already plugged in the
+stick remove it and plug it in again...
+
+To check if everything is working use `openpgp-tool`:
+
+```
+$ openpgp-tool
+Using reader with a card: German Privacy Foundation Crypto Stick v2.0 (0000000000000) 00 00
+Language: de
+Gender: not applicable
+$
+```
+
+This should be all!
+
+#### Firefox
+
+Next you need to enable the OpenSC `PKCS#11` driver in Firefox.
+The library to load is located at `/usr/lib64/opensc-pkcs11.so`. In
+Firefox go to "Preferences" -&gt; "Advanced" -&gt; "Certificates" -&gt;
+"Security Devices" -&gt; "Load", and then enter this path in the
+"Module filename" box.
+
+That should be all for Firefox!
+
+### Approach
+
+It doesn't seem possible to generate a self signed certificate on the Nitrokey,
+it is possible to generate a private and public key on the device, and then
+hook it up to OpenSSL somehow to generate a CSR, but I'm not sure if it is
+possible at that time to immediately generate a self signed certificate.
+
+So, the next obvious choice would be to use the normal IndieCert flow and
+generate a certificate in the browser and export that. This is really not a
+good idea, but it seems the only thing possible right now.
+
+So in order to do that, go to
+[https://indiecert.net/](https://indiecert.net/) and follow the
+normal flow to enroll. Once enrollment is done and the certificate is
+stored in the browser export it to a `PKCS#12` file. This can then
+on the command line be imported in the stick.
+
+You can export the certificate and private key by going to "Preferences" -&gt;
+"Advanced" -&gt; "Certificates" -&gt; "View Certificates" -&gt;
+"Your Certificates". Select the one generated by IndieCert and click
+"Backup...". Firefox will ask for a file path, I used
+`indiecert.p12` and a password, remember this password for later to
+import the `PKSC#12` file in the Nitrokey.
+
+We assume you exported the certificate to `indiecert.p12`. The
+default "Admin PIN" is `12345678`. The default "User PIN" is
+`123456`. Now import it in the key:
+
+```
+pkcs15-init --delete-objects privkey,pubkey --id 3 --store-private-key indiecert.p12 --format pkcs12 --auth-id 3 --verify-pin
+```
+
+This is the output, you will also be asked to enter both the "Admin PIN"
+of the Nitrokey, and the password you provided when exporting the
+`PKCS#12` file in Firefox.
+
+```
+Using reader with a card: German Privacy Foundation Crypto Stick v2.0 (0000000000000) 00 00
+User PIN required.
+Please enter User PIN [Admin PIN]:
+Deleted 2 objects
+error:23076071:PKCS12 routines:PKCS12_parse:mac verify failure
+Please enter passphrase to unlock secret key:
+Importing 1 certificates:
+ 0: /CN=4fad073b801ab6bf0bc21efc0092c625
+```
+
+This now makes it possible to use it in Firefox!
+
+<a href="https://storage.tuxed.net/fkooman/public/upload/blog/nitrokey_firefox_big.png">
+ <img src="https://storage.tuxed.net/fkooman/public/upload/blog/nitrokey_firefox_small.png" width="575" height="323">
+</a>
+
+### Thanks
+
+Special thanks to [elf Pavlik](https://wwelves.org/perpetual-tripper/) for the
+motivation and [@gamamb](https://twitter.com/gamamb) for providing the Nitrokey
+for testing!
+
+### References
+
+- [Nitrokey](https://nitrokey.com/)
+- [IndieCert](https://indiecert.net/)
diff --git a/posts/nm_12_openvpn.md b/posts/nm_12_openvpn.md
new file mode 100644
index 0000000..e5a2e77
--- /dev/null
+++ b/posts/nm_12_openvpn.md
@@ -0,0 +1,50 @@
+---
+title: OpenVPN and NetworkManager 1.2
+published: 2016-05-15
+---
+
+Doing a new round of tests for OpenVPN client support I decided to test how
+well Fedora 24 Beta and Ubuntu 16.04 work. They both have NetworkManager
+1.2 which brings a lot of improvements to the OpenVPN plugin, particularly
+when importing configurations. Particularly I was testing the way imports from
+[eduvpn](https://github.com/eduvpn), a managed VPN service worked.
+
+It turned out it works pretty well, with a minor issue that is already fixed in
+the development branch of NetworkManager. Ubuntu has some issues with DNS
+servers provided over the VPN.
+
+Importing a configuration using NetworkManager 1.2 resulted in a
+small [issue](https://bugzilla.gnome.org/show_bug.cgi?id=739519)
+with `comp-lzo` that was fixed the same day, for release in a next
+point release of NetworkManager 1.2. In the case of eduvpn, the server pushed
+`comp-lzo`:
+
+```
+comp-lzo no
+push "comp-lzo no"
+```
+
+The client had the following:
+
+```
+comp-lzo no
+```
+
+The issue was that OpenVPN import in NetworkManager saw `comp-lzo no` as having
+compression *disabled*, which is only kind of correct: having this option, even
+if it is set to `no` allows the server to override it. Even if the
+server again overrides it with `no` it still does not work when
+`comp-lzo` is missing:
+
+```
+WARNING: 'comp-lzo' is present in remote config but missing in local config, remote='comp-lzo'
+```
+
+Using `comp-lzo yes` in the client configuration allows for the
+import to work correctly and the VPN to work perfectly on Fedora.
+
+On Ubuntu
+there is an additional issue with DNS, particularly in the part that integrates with `dnsmasq`. It was [reported](https://bugs.launchpad.net/ubuntu/+source/network-manager/+bug/1211110) almost 3 years ago, but hasn't been fixed yet.
+
+The work-around is not difficult, but still cumbersome and requires `root`. Disable `dnsmasq` for
+NetworkManager which is used by default on Ubuntu by modifying `/etc/NetworkManager/NetworkManager.conf`. Add a `#` in front of the `dns=dnsmasq` line. Then restart NetworkManager, or simply reboot the system. That should be all!
diff --git a/posts/owncloud_distributions.md b/posts/owncloud_distributions.md
new file mode 100644
index 0000000..b479678
--- /dev/null
+++ b/posts/owncloud_distributions.md
@@ -0,0 +1,73 @@
+---
+title: ownCloud and distributions
+published: 2016-03-30
+---
+
+I want to respond in more detail to the response to my [Tweet](https://twitter.com/ownClouders/status/714797692657000453) to [@ownClouders](https://twitter.com/ownClouders) earlier. I wrote:
+
+> Relevant for the @ownClouders and Debian/Fedora packaging discussion:
+> [http://enricozini.org/blog/2014/debian/debops/](http://enricozini.org/blog/2014/debian/debops/)
+
+This article is written by a software developer who takes Debian as
+a base operating system and develops his software targeting Debian stable. It
+brings him many benefit like "free" security updates and bug fixes in
+the operating system and the libraries he needs that are already available in
+Debian. That way he can focus on just his software and not the dependencies,
+or worry about moving targets.
+
+### Responses
+
+> @fkooman it's great if you have the time to support old platforms... But for
+> a big project, it is a huge investment with minor benefit
+
+The recommended target distribution to install the latest version of ownCloud
+9.0 on [is](https://doc.owncloud.org/server/9.0/admin_manual/installation/system_requirements.html)
+Red Hat Enterprise Linux 7. This distribution is using PHP 5.4, which is still
+supported by ownCloud. This is, at least in the PHP world, a very old platform
+that is being supported.
+
+About the benefits of distribution packaging: I think the most visible benefit of providing
+official distribution packages would be for the
+community and the users. Only having to do `yum install owncloud`
+and `yum update` to have a working setup without worrying about
+verifying signatures and keeping it up to date is not a minor benefit! But also
+for the developers there are some big benefits:
+
+* Quality: by using the official packaging guidelines and untangling the
+ dependencies in separate packages there is an incentive to use high quality
+ dependencies that can easily be packaged and to limit the number of
+ dependencies. Dependencies are not free even if they only seem a
+ `composer require` away;
+* Testing: on most PHP packages in Fedora the included test suite in run during
+ build on the exact same version of the components they will later run on
+ ([example](https://apps.fedoraproject.org/packages/php-guzzlehttp-guzzle/sources/spec/));
+* Maintenance: by separating the application in its components maintenance
+ becomes easier. When fixing a bug in a dependency it is easier to just update
+ the package for the dependency, leaving the rest alone;
+* Collaboration: some of the work of packaging can be shared among other
+ packagers who require the same dependencies, many are already packaged. As a
+ result more users than just the ownCloud users can benefit of the work;
+
+To me, these are convincing reasons to package the (web) applications I
+develop immediately for Fedora/CentOS. Initially it is a little more work, but
+later on the costs reduce substantially if you only have to worry about your
+application and not the dependencies once they are packaged and reliable.
+
+> @fkooman and sadly, volunteers seem not interested, neither do customers
+> want to pay for it....
+
+Volunteers
+[were](https://www.happyassassin.net/2015/08/29/looking-for-new-maintainer-for-fedora-epel-owncloud-packages/)
+[interested](https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=816376), but got
+demotivated by the problems they had to deal with.
+
+Given the reasons above for choosing distribution packaging, I think customers
+*are* paying for it already, considering it is really QA and software
+hygiene. I'm pretty sure enterprise customers would really like to have
+software they can install on a server and leave alone for a year or longer
+without requiring complicated upgrade processes, while only installing the
+occasional bug fix. Just for this reason I think it is important that the
+developers of the software themselves take on the packaging for the supported
+distributions and follow the platform conventions as much as possible to get
+the highest possible quality software, and in the process bring extra value to
+other projects running on the same platform.
diff --git a/posts/proposed_changes_to_indieauth_protocol.md b/posts/proposed_changes_to_indieauth_protocol.md
new file mode 100644
index 0000000..f1a6c28
--- /dev/null
+++ b/posts/proposed_changes_to_indieauth_protocol.md
@@ -0,0 +1,89 @@
+---
+title: Proposed Changes to IndieAuth Protocol
+published: 2015-03-04
+modified: 2015-03-06
+---
+
+**Update (2015-03-06)**: Aaron Parecki replied to this proposal
+[here](https://aaronparecki.com/articles/2015/03/05/1/re-proposed-changes-to-indieauth-protocol).
+I agree with his reply as it turns out IndieAuth is also used for
+authorization in addition to authentication.
+
+### Introduction
+
+This post proposes a few minimal changes to the IndieAuth protocol as well as
+their rationale. These changes were inspired by creating an alternative but
+mostly compatible IndieAuth implementation called IndieCert, using client
+certificates to authenticate users, or actually browsers. More information
+on IndieCert can be found in this [blog](indiecert.html) post.
+
+#### Optional `client_id`
+
+Currently the protocol expects the use of the `client_id`
+parameter in the authentication request. This does not seem necessary as it
+is never used, just a remnant of OAuth 2.0. The `redirect_uri` is
+enough to establish the relying party's identity. So the proposal is to make
+`client_id` support OPTIONAL both for relying party as well as the
+IndieAuth services.
+
+#### CSRF protection
+
+It is advisable to implement CSRF protection. The `state` parameter
+can be used for that, or a new parameter, like `csrf_token`, as
+proposed by "SaferWeb: OAuth2.a or Let's Just Fix It" MUST be implemented.
+
+This will protect against an attacker obtaining a `code` and
+tricking the user's browser to go to the relying party's callback endpoint,
+thus gaining access to the server on the attacker's behalf and potentially
+leaking private data to the attacker's account.
+
+The CSRF token (or state) needs to be saved in a browser session that is
+created when the user tries to login to the relying party. The CSRF token is
+compared to the token specified on the callback URL after the user grants
+permission to the relying party to obtain the user's identity.
+
+
+#### Terminology: authentication instead of authorization
+
+IndieAuth is actually used for *authentication* and not
+*authorization* as is mentioned on the "Distributed IndieAuth" page.
+This should be modified to talk about authentication instead. Also the name of
+the `authorization_endpoint` should be changed to
+`authentication_endpoint`.
+
+#### Additional "verify" endpoint
+
+The "auth" endpoint in IndieAuth is currently used both for initiating the
+authentication (GET) as well as verifying the authentication code (POST). In
+order to support the option to ask for user consent before the identity of the
+user is released, it makes sense to have a separate verification endpoint as
+the POST on the authentication endpoint will be used for a form submit.
+
+This is also relevant in the case of "Distributed IndieAuth" where the
+user mentions the `authorization_endpoint`, as a link relation on
+their home page. The proposal is to also allow for (optionally) defining a
+`verification_endpoint` link relationship on the user's homepage.
+For example:
+
+```
+<link rel="authentication_endpoint" href="https://indiecert.net/auth">
+<link rel="verification_endpoint" href="https://indiecert.net/verify">
+```
+
+#### Content negotiation for "verify" endpoint
+
+Currently the IndieAuth protocol uses a
+`application/x-www-form-urlencoded` formatted *response*
+instead of the currently more popular `application/json` response
+format, e.g. in OAuth 2.0. It is proposed to support "Content Negotiation" by
+checking the HTTP `Accept` header in the verification request and
+returning either `application/x-www-form-urlencoded` or
+`application/json` depending on the `Accept` header. The
+default can be either of those, but both MUST be supported.
+
+### References
+
+- [IndieAuth](https://indieauth.com)
+- [IndieCert](https://indiecert.net)
+- [Distributed IndieAuth](https://indiewebcamp.com/distributed-indieauth)
+- [SaferWeb: OAuth2.a or Let's Just Fix It](http://homakov.blogspot.de/2012/08/saferweb-oauth2a-or-lets-just-fix-it.html)
diff --git a/posts/wireless_router_vpn.md b/posts/wireless_router_vpn.md
new file mode 100644
index 0000000..4beafad
--- /dev/null
+++ b/posts/wireless_router_vpn.md
@@ -0,0 +1,38 @@
+---
+title: Wireless Routers and VPNs
+published: 2015-07-30
+---
+
+I've been playing around with [OpenWrt](https://openwrt.org) and
+[Freifunk](http://freifunk.net/). There are special OpenWrt images
+for Freifunk. They are slightly modified vanilla OpenWrt
+images. They include for instance [OpenVPN](https://openvpn.net/).
+The interesting approach here is that all traffic from the access point will be
+routed over the VPN, thus eliminating the liability for the provider of the
+access point: the traffic of the users on the Freifunk access point cannot
+(easily) be linked back to the ISP of the user. Especially in Germany this is
+[important](http://www.zdnet.com/article/file-sharing-in-germany-could-the-cost-of-getting-caught-be-about-to-come-down/)
+if you want to share your Internet connection.
+
+The Freifunk images also support mesh networking, so it becomes possible to
+connect to Freifunk if your own router can connect to another Freifunk access
+point and relay the traffic. This way it is possible to make a mesh, and only
+one of the access points in the mesh needs to have an actual Internet
+connection that then can be shared. Brilliant!
+
+I used the
+[TP-Link TL-WR703N](http://wiki.openwrt.org/toh/tp-link/tl-wr703n)
+for Freifunk. It is not "officially" supported, but it was very easy to
+generate an image for it. It is a bit tricky to get working as there is only
+one ethernet port on the WR703N which is configured by default as the LAN
+port. It should be configured as the WAN port, perhaps I can modify the
+profile of the Freifunk firmware a bit to make it act as the WAN port by
+default.
+
+### eduroam
+
+This could also have a wider application, for example for [eduroam](https://eduroam.org).
+Together with [eduVPN](https://wiki.surfnet.nl/display/eduvpn/eduVPN) it makes for a compelling use case to use
+for instance the WR703N, available for less than $25 to promote eduroam
+everywhere from your home to libraries and cafes around the city. Minimal
+investment, great benefit for students and researchers!