# Client certificates and Apache



## xy16644 (Jul 26, 2009)

Does anyone have a guide that a newbie like me can use to setup client side certificates with FreeBSD and Apache.

I tried a few articles online but they are more aimed at Linux users and am finding it confusing trying to "translate" that into FreeBSD...

I basically have a subfolder off a web site like:

https://www.mydomain.com/secure

and I would like to JUST secure the "secure" sub folder.

Thank you.


----------



## aragon (Jul 26, 2009)

Does this contain the information you need?

I'm assuming you know how to generate certificates...


----------



## xy16644 (Jul 26, 2009)

Thanks but I have already looked at that link. I am relatively familiar with certificates but not so much on FreeBSD.

I setup a test alias in Apache as follows:


```
Alias /client "/usr/local/www/client/"

<Directory "/usr/local/www/client/">
Options Indexes FollowSymLinks
AllowOverride All
Order allow,deny
Allow from all
SSLVerifyClient require
SSLVerifyDepth 1
SSLCACertificateFile /usr/local/openssl/certs/mydomain.com-CAcert.pem
</Directory>
```

But it still lets me view my test page without prompting me to have a valid client side cert.

If I comment out the following options:


```
Alias /client "/usr/local/www/client/"

<Directory "/usr/local/www/client/">
#Options Indexes FollowSymLinks
#AllowOverride All
#Order allow,deny
#Allow from all
SSLVerifyClient require
SSLVerifyDepth 1
SSLCACertificateFile /usr/local/openssl/certs/mydomain.com-CAcert.pem
</Directory>
```

I then get:


```
Forbidden
You don't have permission to access /client/index.html on this server.
```

But still no prompt :\


----------



## aragon (Jul 26, 2009)

It shouldn't matter that this is FreeBSD - Apache works the same here as other unixes. 

Stupid question maybe, but are browsing your server via SSL? (ie. https:// in  browser address bar)


----------



## xy16644 (Jul 27, 2009)

The test site I setup is not using SSL but when I finish testing this successfully I will be using SSL AND client side certificates.


----------



## aragon (Jul 27, 2009)

xy16644 said:
			
		

> The test site I setup is not using SSL


How do you expect it to work then without SSL?


----------



## xy16644 (Jul 27, 2009)

Sorry wasn't thinking when I posted that! I tried it with SSL but still no joy...


----------



## xy16644 (Jul 28, 2009)

I'm quite baffled about configuring client side certificates in Apache.

I setup a new test site in Apache as follows:


```
Alias /test "/usr/local/www/test/"

<Directory "/usr/local/www/test/">
Options Indexes FollowSymLinks
AllowOverride All
Order allow,deny
Allow from all
SSLRequireSSL
SSLVerifyClient require
</Directory>
```

If I browse the site httpS://www.mydomain.com/test it works perfectly over SSL. As soon as I enable "SSLVerifyClient require" then I can't browse the site anymore. It doesn't even prompy me to select a certificate to allow me access to that part of the site, whys this?


----------



## xy16644 (Jul 28, 2009)

This is what /var/log/httpd-error.log says:


```
[Tue Jul 28 15:47:32 2009] [error] Re-negotiation handshake failed: Not accepted by client!?
```


----------



## aragon (Jul 28, 2009)

I haven't seen that before.  What browser are you using?


----------



## xy16644 (Jul 28, 2009)

Thats when testing it with IE8.

When I try from Firefox 3.5.1 I get:


```
Secure Connection Failed

An error occurred during a connection to www.mydomain.com.

SSL peer was unable to negotiate an acceptable set of security parameters.

(Error code: ssl_error_handshake_failure_alert)


    *   The page you are trying to view can not be shown because the authenticity of the received data could not be verified.

    *   Please contact the web site owners to inform them of this problem. Alternatively, use the command found in the help menu to report this broken site.
```


----------



## xy16644 (Jul 28, 2009)

The thing I dont understand is on the Apache site:

http://httpd.apache.org/docs/2.0/ssl/ssl_howto.html#accesscontrol

it says I should have the following directive:


```
SSLCACertificateFile conf/ssl.crt/ca.crt
```

But I dont have any .crt files for my certificates, They are all in PEM format.

Does anyone have this working that could maybe post an example conf file for Apache ;-)


----------



## xy16644 (Jul 28, 2009)

In one article I read it says:

Install the local CA's certificate into the Apache directory structure.


```
install -m 644 -o root -g sys ca.crt /usr/local/apache2/conf/ssl.crt/
```

Again, I dont have any .crt files and I also dont have an Apache conf directory (not that I can find anyway!).

Any ideas? I'm not sure what else to do...


----------



## aragon (Jul 28, 2009)

.crt is just a file extension.  It is used to denote a file containing a certificate only (as opposed to a private key or certificate+private key).  Apache uses openssl, which needs PEM formatted files, so what you have should be fine once you've configured Apache to use the right files.

You should have these 3 things for apache:

1. CA certificate
2. Server certificate
3. Server private key

Do you have all of these setup?


----------



## xy16644 (Jul 28, 2009)

I have the following I have created with OpenSSL:


http://www.mydomain.com-CAcert.pem
http://www.mydomain.com-encrypted-CAkey.pem

http://www.mydomain.com-cert.pem
http://www.mydomain.com-encrypted-key.pem
http://www.mydomain.com-unencrypted-key.pem


----------



## aragon (Jul 28, 2009)

Ok, good.  You need to configure these:


```
SSLCertificateFile /path/to/www.mydomain.com-cert.pem
SSLCertificateKeyFile /path/to/www.mydomain.com-unencrypted-key.pem
SSLCACertificateFile /path/to/www.mydomain.com-CAcert.pem
SSLVerifyClient require
SSLVerifyDepth 1
```

Obviously replacing "/path/to" to the real path to each of those files.  Verify depth must be set higher if you're signing more than 1 deep.

You need to make sure they're not overridden elsewhere in your config.  Check that apache's SSL is not being misconfigured in an include somewhere.


```
grep -i include /usr/local/etc/apache2/httpd.conf
```

And check how SSLCipherSuite, SSLOptions, and SSLRequire is setup - it sounds like one of those might be breaking browser compatibility.


----------



## xy16644 (Jul 28, 2009)

Thanks for that reply!

I put those entries into my "test.conf" file (not httpd.conf) and when I restarted Apache it said:


```
server# /usr/local/etc/rc.d/apache22 restart
Performing sanity check on apache22 configuration:
Syntax error on line 9 of /usr/local/etc/apache22/Includes/test.conf:
SSLCertificateFile not allowed here
```

If I run 


```
grep -i include /usr/local/etc/apache22/httpd.conf
```

I get:


```
server# grep -i include /usr/local/etc/apache22/httpd.conf
LoadModule include_module libexec/apache22/mod_include.so
    #   Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews
# Possible values include: debug, info, notice, warn, error, crit,
    # If you include a trailing / on /webpath then the server will
    # To parse .shtml files for server-side includes (SSI):
    # (You will also need to add "Includes" to the "Options" directive.)
    #AddOutputFilter INCLUDES .shtml
# included to add extra features or to modify the default configuration of
#Include etc/apache22/extra/httpd-mpm.conf
#Include etc/apache22/extra/httpd-multilang-errordoc.conf
#Include etc/apache22/extra/httpd-autoindex.conf
#Include etc/apache22/extra/httpd-languages.conf
#Include etc/apache22/extra/httpd-userdir.conf
#Include etc/apache22/extra/httpd-info.conf
#Include etc/apache22/extra/httpd-vhosts.conf
#Include etc/apache22/extra/httpd-manual.conf
#Include etc/apache22/extra/httpd-dav.conf
#Include etc/apache22/extra/httpd-default.conf
Include etc/apache22/extra/httpd-ssl.conf
Include etc/apache22/Includes/*.conf
```


----------



## aragon (Jul 28, 2009)

Please post your test.conf and extra/httpd-ssl.conf?


----------



## xy16644 (Jul 28, 2009)

aragon said:
			
		

> Please post your test.conf and extra/httpd-ssl.conf?



Here we go:

test.conf:


```
Alias /test "/usr/local/www/test/"

<Directory "/usr/local/www/test/">
Options Indexes FollowSymLinks
AllowOverride All
Order allow,deny
Allow from all
SSLRequireSSL
SSLCertificateFile /usr/local/openssl/certs/mydomain.com-cert.pem
SSLCertificateKeyFile /usr/local/openssl/certs/mydomain.com-unencrypted-key.pem
SSLCACertificateFile /usr/local/openssl/certs/mydomain.com-CAcert.pem
SSLVerifyClient require
SSLVerifyDepth 1
</Directory>
```

extra/httpd-ssl.conf:


```
Listen 443

AddType application/x-x509-ca-cert .crt
AddType application/x-pkcs7-crl    .crl

SSLPassPhraseDialog  builtin

SSLSessionCache        "shmcb:/var/run/ssl_scache(512000)"
SSLSessionCacheTimeout  300

SSLMutex  "file:/var/run/ssl_mutex"

<VirtualHost _default_:443>

DocumentRoot "/usr/local/www/securesite/"
ServerName www.mydomain.com:443
ServerAdmin admin@mydomain.com
ErrorLog "/var/log/httpd-error.log"
TransferLog "/var/log/httpd-access.log"

SSLEngine on

SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL

SSLCertificateFile "/usr/local/openssl/certs/www.mydomain.com-cert.pem"



SSLCertificateKeyFile "/usr/local/openssl/certs/www.mydomain.com-unencrypted-key.pem"

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


CustomLog "/var/log/httpd-ssl_request.log" \
          "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"
ProxyPass /webmin/ http://www.mydomain.com:10000
ProxyPassReverse /webmin/ http://www.mydomain.com:10000

</VirtualHost>
```

I removed all the comments from httpd-ssl.conf as it was a rather lenghty file! :e


----------



## aragon (Jul 28, 2009)

(Backup and) Delete test.conf and replace extra/httpd-ssl.conf with:


```
Listen 443

AddType application/x-x509-ca-cert .crt
AddType application/x-pkcs7-crl    .crl

SSLPassPhraseDialog  builtin

SSLSessionCache        "shmcb:/var/run/ssl_scache(512000)"
SSLSessionCacheTimeout  300

SSLMutex  "file:/var/run/ssl_mutex"

<VirtualHost _default_:443>

DocumentRoot "/usr/local/www/securesite/"
ServerName www.mydomain.com:443
ServerAdmin admin@mydomain.com
ErrorLog "/var/log/httpd-error.log"
TransferLog "/var/log/httpd-access.log"

SSLEngine on

SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL

SSLCACertificateFile /usr/local/openssl/certs/mydomain.com-CAcert.pem
SSLCertificateFile "/usr/local/openssl/certs/www.mydomain.com-cert.pem"
SSLCertificateKeyFile "/usr/local/openssl/certs/www.mydomain.com-unencrypted-key.pem"

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


CustomLog "/var/log/httpd-ssl_request.log" \
          "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"
ProxyPass /webmin/ http://www.mydomain.com:10000
ProxyPassReverse /webmin/ http://www.mydomain.com:10000

Alias /test "/usr/local/www/test/"
<Directory "/usr/local/www/test/">
Options Indexes FollowSymLinks
AllowOverride All
Order allow,deny
Allow from all
SSLRequireSSL
SSLVerifyClient require
SSLVerifyDepth 1
</Directory>

</VirtualHost>
```


----------



## xy16644 (Jul 28, 2009)

OK, I deleted the test.conf file and replaced the following in httpd-ssl.conf:


```
SSLCACertificateFile /usr/local/openssl/certs/mydomain.com-CAcert.pem

Alias /test "/usr/local/www/test/"

<Directory "/usr/local/www/test/">
Options Indexes FollowSymLinks
AllowOverride All
Order allow,deny
Allow from all
SSLRequireSSL
SSLVerifyClient require
SSLVerifyDepth 1
</Directory>

</VirtualHost>
```

Am still getting no prompt for a certificate though.

Still getting these in the /var/log/httpd-error.log:


```
[Tue Jul 28 21:32:48 2009] [error] Re-negotiation handshake failed: Not accepted by client!?
```


----------



## xy16644 (Jul 28, 2009)

In the /var/log/httpd-access.log I get:


```
192.168.0.10 - - [28/Jul/2009:21:32:48 +0100] "GET /test/index.html HTTP/1.1" 403 -
192.168.0.10 - - [28/Jul/2009:21:38:45 +0100] "GET /test/ HTTP/1.1" 403 -
```


----------



## aragon (Jul 28, 2009)

Ok, I assume you have generated a client certificate and have installed it into your browser?


----------



## xy16644 (Jul 28, 2009)

I have a file called mydomain.com-CAcert.cer which I have imported into the browser as a trusted CA.

The problem is that I am not even getting the prompt to select the certificate when browsing the protected site in the browser as shown here:

http://www.securityfocus.com/infocus/1823

(figure 1)


----------



## aragon (Jul 28, 2009)

Perhaps newer browsers don't even bring up a prompt if there are no client certificates installed?  Seeing as you will need a client certificate anyway, I think you should generate one and import it into the browser now.


----------



## xy16644 (Jul 28, 2009)

Don't think so, both Firefox 3.5.1 and IE8 are behaving this way.

I know at one client I did some work at, they had a client side certificate for authentication in IE7 and IE8 and they got prompted with that window so they could select the correct certificate to authenticate with. On a test machine with no cert installed it would still prompt except there would be no cert to choose from.

On my test machine here I have already imported the cert into IE and told it that its a trusted CA.

Its like theres a config issue here preventing this from working.


----------



## xy16644 (Jul 29, 2009)

Any other suggestions I can try to get this to work?

The guides on the web make this sound so easy and yet I am really battling to even get the prompt screen to select a certificate to authenticate to a web site.

Any ideas?


----------



## aragon (Jul 29, 2009)

I've done it a handful of times, but not in the last year or two.  As far as I recall, it was easy and works very well.  One of my customers uses it extensively for authenticating their customers.  I'm out of ideas with your setup though, and am curious to know what the problem is if/when you find it.


----------



## xy16644 (Jul 29, 2009)

I'm totally baffled too. The logfile doesn't really give enough detail to troubleshoot this.

Am gonna have to keep researching it. I really appreciate your help (and patience) aragon!


----------



## bschop (Jan 8, 2010)

*Any luck with this ?*

I've run into the same problem, and am hoping you have figured out a workaround.

In case you haven't, I've found the following :
  - I can easily get an entire Virtual Host to proper prompt for a client certificate 
  - I can get a given location within a non-ssl site to upgrade to client side SSL and prompt for a certificate

  What I can't do is get a given location within a secured ( https ) site to prompt for a client cert.  This, I believe is the same problem of the original post.

  Oh, and I am using apache 2.2.14 on FreeBSD 7.2


----------



## Spectrum (Dec 24, 2010)

Hi, I would be very interested if anyone knows a solution/explanation for the above problem. I am experiencing the exact same problem with Apache v2.2.14 on Win XP SP3.

I am testing on the localhost and place my config directives inside :-


```
<VirtualHost _default_:443>
</VirtualHost>
```

All is well with SSL and certificates until I add in the line :-


```
SSLVerifyClient require
```
ie. to require SSL Client Authentication.

This causes errors in all browsers IE8/FF/Chrome/Safari/Opera.

In FF the error is :-

```
SSL peer was unable to negotiate an acceptable set of security parameters.
(Error code: ssl_error_handshake_failure_alert)
```

I have created all certificates and entered all configuration directives correctly as described in the Apache documentation.

And, it makes no difference whether I install client certificate on the browser.

As OP said, a request dialog should be appearing asking user to select client certificate.

But its just not happening. I spent a lot of time looking into this, and would like to know what's up.

Then I can get on with my life OK?

And - Merry Xmas to all!


----------



## Spectrum (Jan 7, 2011)

I have managed to solve this problem on my own system, and perhaps this is relevant to the OP's problem also - its not something that is mentioned in the Apache documentation.

One thing that makes client cert different from web site cert is that it must contain the private key. TLS handshake requires client to have the private key. A web site cert contains only public key<->identity association (plus digital signature).

This composite file has a standard format called PKCS#12 (.p12 file extension). To create such a file enter :-

`openssl pkcs12 -export -out client_a.p12 -in client_a.crt -inkey client_a.key`

where client_a.crt is the client cert and client_a.key is the private key file.

Then the browser can accept import of the file client_a.p12 as a 'Personal Certificate'. I tested this on Firefox/Chrome/Opera/IE8, and they all work, with the browser displaying a dialog for client cert choice on accessing the secure page.

However the client cert MUST be imported into the browser first, it will not just prompt when you first access the secure site.

HTH.


----------

