Verifying the domain of a certificate in OpenSSL

2019-03-29 11:38发布

I need to verify the domain of an X509 certificate using C-land OpenSSL.

My understanding is that the library doesn't do this for me, and that I have to implement roughly the following algorithm:

  1. If the dnsName field of the subjectAlternativeName extension is present, set name to that value.
  2. Otherwise, set name to the CN field of the subject.
  3. Compare name against the requested hostname, allowing each asterisk to match [A-Za-z0-9_]+, but not 'dot' (.).

It seems to me that there should be plenty of code kicking around to do this, but I haven't found any.

Can anyone find an example of this? Or alternatively, sanity-check my algorithm?

EDIT: This is what I came up with: https://gist.github.com/2821083. It seems really strange that OpenSSL would leave this up to calling code.

标签: openssl ssl x509
2条回答
We Are One
2楼-- · 2019-03-29 11:58

You are pretty much spot on - though beware of subject Alternative names and raw IP addresses and FQDNs. You may want to steal

BOOL SSL_X509_getIDs(apr_pool_t *p, X509 *x509, apr_array_header_t **ids)

and related friends from http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/ssl/ssl_util_ssl.c and the callee in ssl_engine_init.c (which is by the way the server side) for all the options.

As you are acting on the openssl callback - also consider the date & time and the chain if you've not provided that already in the CTX.

Dw.

查看更多
Ridiculous、
3楼-- · 2019-03-29 12:01

It seems really strange that OpenSSL would leave this up to calling code.

Yes, its very problematic omission in practice because so many application's don't realize they must manually perform the check.

OpenSSL 1.1.0 will include hostname verification (it in HEAD now (as of SEPT 2013)). According to the change logs, there's a -verify_name option, and apps.c responds to the -verify_hostname switch. But s_client does not respond to either switch, so its unclear how hostname checking will be implemented or invoked for a client.


If the dnsName field of the subjectAlternativeName extension is present, set name to that value.

There could be multiple Subject Alternate Names (SAN), so be prepared for more than one.

Otherwise, set name to the CN field of the subject.

I believe you need to check that for a match, too.

Compare name against the requested hostname, allowing each asterisk to match [A-Za-z0-9_]+, but not 'dot' (.).

Its much more painful. You also have to ensure you're not matching a gTLD or ccTLD. For example, you don't want to match on a certificate issued against the gTLD *.com. That certificate was probably issued by a bad guy ;)

ccTLDs are like *.eu, *.us, or இலங்கை (nic.lk). There's some 5000 or so of them and Mozilla offers a list at http://publicsuffix.org/. The raw list is at https://mxr.mozilla.org/mozilla-central/source/netwerk/dns/effective_tld_names.dat?raw=1.


It seems to me that there should be plenty of code kicking around to do this, but I haven't found any.

In addition to van Gulik's suggestion, you can also try Curl. I'm fairly certain Curl contains hostname matching code.


You can even verify the certificates are well formed. The group responsible in the context of the Web is the CA/Browser forums. They have baseline and extended requirements for creating certificates:

In the baseline docs, you will find, for example, an IP listed as the Common Name (CN) must also be listed in the Subject Alternate Names (SAN).

In the extended docs, you will find that reserved IPs (RFC 1918) cannot be present in a extended validation (EV) certificate; and EV certificates cannot contain wild cards.

查看更多
登录 后发表回答