In yesterday's post looking at MintChip's hosted API's crypto, I noticed that MintChip's certificate authority does not have any name constraints. This was surprising, because this seemed like a simple and obvious issue with an otherwise well designed system... But after some experimentation, it seems that OpenSSL simply ignores nameConstraints, so they would be mostly worthless even if they were used.
Adding nameConstraints to MintChip's CA
This can be seen by adding some nameConstraints to MintChip's certificate authority and re-signing it using a new, trusted, certificate authority.
Note that all files referenced here can be found at /uploads/adventures_in_x509_ignored_nameconstraints/.
A new certificate authority is created and the add_name_constraints.py to add nameConstraints to MintChip's CA's certiificate, creating mintchip_with_constraints.crt, which will be signed by the new CA:
$ openssl req -new -x509 -keyout trusted_ca.pem -out trusted_ca.pem -nodes ... Organizational Unit Name (eg, section) : New Trusted Authority ... $ ./add_name_constraints.py trusted_ca.pem mintchip_ca.crt > mintchip_with_constraints.crt $ openssl x509 -noout -text -in mintchip_with_constraints.crt Data: ... Issuer: OU=New Trusted Authority Subject: CN=Remote MintChip Certificate Authority, OU=Remote MintChip, O=Royal Canadian Mint, C=CA ... X509v3 extensions: ... X509v3 Name Constraints: critical Permitted: DNS:does_not_exist.com
Testing the Constraints
The constraints can now be tested using OpenSSL's s_client:
$ cat trusted_ca.pem mintchip_with_constraints.crt > ca_list.crt $ openssl s_client -CAfile ca_list.crt -connect remote.mintchipchallenge.com:443 CONNECTED(00000003) depth=2 /C=AU/ST=Some-State/O=Internet Widgits Pty Ltd/OU=New Trusted Authority verify return:1 depth=1 /CN=Remote MintChip Certificate Authority/OU=Remote MintChip/O=Royal Canadian Mint/C=CA verify return:1 depth=0 /CN=remote.mintchipchallenge.com/OU=Remote MintChip Server/O=Royal Canadian Mint/C=CA verify return:1 ... SSL-Session: ... Verify return code: 0 (ok) ---
- Our "New Trusted Authority" is used to verify MintChip's Certificate Authority (first six lines).
- The SSL session is successfully verified (the last line).
This suggests that OpenSSL is not checking name constraints.
To double check that our certificat authority is actually being consulted, the same test can be run, except using only the mintchip_with_constraints.crt certificate:
$ openssl s_client -CAfile mintchip_with_constraints.crt \ -connect remote.mintchipchallenge.com:443 CONNECTED(00000003) depth=1 /CN=Remote MintChip Certificate Authority/OU=Remote MintChip/O=Royal Canadian Mint/C=CA verify error:num=2:unable to get issuer certificate issuer= /C=AU/ST=Some-State/O=Internet Widgits Pty Ltd/OU=New Trusted Authority verify return:0 ... SSL-Session: ... Verify return code: 2 (unable to get issuer certificate) ---
The verify now fails, so it's fairly certain that the certificate chain is working as expected.
Adding dirName nameConstraints
Applications conforming to this profile MUST be able to process name constraints that are imposed on the directoryName name form and SHOULD be able to process name constraints that are imposed on the rfc822Name, uniformResourceIdentifier, dNSName, and iPAddress name forms.
On closer inspection of RFC 5280, it turns out that applications are only required to check name constraints which are imposed on directory names.
This poses a slight challenge, as (for various reasons) pyOpenSSL cannot create a nameConstraints extension which imposes a dirName constraint.
The OpenSSL command line tools can be used to create a new certificate which does contain nameConstraints on a dirName (see the definition in name_constraints_on_dirNames.cfg), then pyOpenSSL can load that certificate and copy the constraints into the target:
$ openssl req -new -x509 -nodes -config name_constraints_on_dirNames.cfg \ > -out dirName_constraints.crt ... $ ./add_name_constraints.py trusted_ca.pem mintchip_ca.crt \ > dirName_constraint.crt > mintchip_with_dirName_constraints.crt ... $ openssl x509 -noout -text -in mintchip_with_dirName_constraints.crt Certificate: ... X509v3 extensions: ... X509v3 Name Constraints: critical Permitted: DirName: CN = bad_common_name
: OpenSSL expects the value of the dirName=... to be a name which is looked up in the configuration database (ex, nameConstraints = permitted;dirName=some_section_), but pyOpenSSL does not provide a configuration database.
Testing the dirName Constraint
Testing this new certificate with s_client:
$ cat trusted_ca.pem mintchip_with_dirName_constraints.crt \ > > ca_list_with_dirName_constraints.crt $ openssl s_client -CAfile ca_list_with_dirName_constraints.crt \ > -connect remote.mintchipchallenge.com:443 CONNECTED(00000003) depth=2 /C=AU/ST=Some-State/O=Internet Widgits Pty Ltd/OU=New Trusted Authority verify return:1 depth=1 /CN=Remote MintChip Certificate Authority/OU=Remote MintChip/O=Royal Canadian Mint/C=CA verify return:1 depth=0 /CN=remote.mintchipchallenge.com/OU=Remote MintChip Server/O=Royal Canadian Mint/C=CA verify return:1 ... SSL-Session: ... Verify return code: 0 (ok) ---
Still no love. It sure looks like OpenSSL simply ignores the nameConstraints field on certificate authorities.
On Twitter, Dan Kaminsky was kind enough to "confirm" my suspicions:
OpenSSL does not check nameConstraints. Yay.
The Royal Canadian Mint announced a challenge last week, calling for developers to build software which uses MintChip. MintChip is a proposed digital currency which is decentralized, anonymous, and offline. The (currently scarce) details of the device and developer challenge can be found at mintchipchallenge.com.
A couple of friends and I have signed up to build something, and we just got the private keys and certificates necessary to interact with the "hosted MintChip" API.
Before I go into more detail, let me first explain: payments are processed by the "trusted" MintChip hardware. This hardware can either be attached directly to the device facilitating a payment (for example, a smart phone), or hosted by a trusted 3rd party, allowing the MintChip to be used from any internet-connected device.
This is called the "hosted API", and this post deals with the cryptography used for authentication and privacy by the current implementation of the hosted API.
Once my physical devices arrive, I will write a post about them, provided they are sufficiently interesting.
: at least, trusted in theory; if the hardware is compromised it would be possible to forge transactions (ex, double-spend, create new money, etc).
The Hosted API
- Everything here is educated guesswork, based only on the sparse MintChip documentation and the PKCS12 file which is used to access the hosted API.
- I am an x509 enthusiast but not an expert. If you are, I would very much appreciate it if you pointed out any inaccuracies or omissions.
- This is a developer preview of a proof-of-concept. There is no guarantee that the security of the final system will look anything at all like the system I'm describing here.
The first thing you'll notice when trying to access the hosted HTTPS API is that it signed with an "invalid" certificate (although this is for a sensible reason; keep reading):
$ curl https://remote.mintchipchallenge.com curl: (60) SSL certificate problem, verify that the CA cert is OK. Details: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed More details here: http://curl.haxx.se/docs/sslcerts.html
And connecting anyway yields a 403 Forbidden (also, that they are running ASP.NET):
$ curl -Ik https://remote.mintchipchallenge.com HTTP/1.1 403 Forbidden Server: Microsoft-IIS/7.5 X-Powered-By: ASP.NET
HTTPS Server Certificate
Grabbing and dumping the certificate they are using:
$ openssl s_client -connect remote.mintchipchallenge.com:443 -showcerts \ > | openssl x509 -noout -text ... Certificate: Data: Version: 3 (0x2) Serial Number: 2 (0x2) Signature Algorithm: sha1WithRSAEncryption Issuer: CN=Remote MintChip Certificate Authority, OU=Remote MintChip, O=Royal Canadian Mint, C=CA Validity Not Before: Mar 6 08:25:42 2012 GMT Not After : Mar 7 08:25:42 2013 GMT Subject: CN=remote.mintchipchallenge.com, OU=Remote MintChip Server, O=Royal Canadian Mint, C=CA Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public Key: (1024 bit) Modulus (1024 bit): 00:8e:1c:52:2f:c7:62:7d:05:0b:4a:80:4f:cb:91: ... 5a:90:60:58:f9:43:c8:bc:f1 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Basic Constraints: CA:FALSE X509v3 Key Usage: Key Encipherment, Key Agreement X509v3 Extended Key Usage: TLS Web Server Authentication Signature Algorithm: sha1WithRSAEncryption 58:34:a3:bd:f3:8d:17:b2:eb:4e:ed:f6:58:b0:13:3b:8c:79: ... 91:0d:59:81 ...
Note that the certificate is issued by "Remote MintChip Authority". I suspect that MintChip chose to use their own CA both for simplicity (they don't need to deal with a 3rd party) and security. Apart from that, this certificate looks fairly standard (although I don't fully understand the implications of the "Key Agreement" flag).
Developer Account PKCS12 Files
Next, once my developer account was approved, I was sent two PKCS12 files (and the passwords used to decrypt them), corresponding to (I assume) two hosted MintChips.
: actually, my friend's developer account - mine hasn't been approved yet.
Unpacking each of these PKCS12 files yields one private key and two certificates:
$ openssl pkcs12 -nodes -passin pass:hunter2 -info -in 1310000000008139.p12 MAC Iteration 1024 MAC verified OK PKCS7 Data Shrouded Keybag: pbeWithSHA1And3-KeyTripleDES-CBC, Iteration 1024 Bag Attributes localKeyID: 82 8F 5D AD 42 DC C9 EA 25 2C 6E 65 C0 DB B8 20 52 7D 1D 15 friendlyName: 1310000000008139 Remote MintChip Client (Developer Challenge) Key Attributes: <No Attributes> -----BEGIN RSA PRIVATE KEY----- ... -----END RSA PRIVATE KEY----- PKCS7 Encrypted data: pbeWithSHA1And40BitRC2-CBC, Iteration 1024 Certificate bag Bag Attributes localKeyID: 82 8F 5D AD 42 DC C9 EA 25 2C 6E 65 C0 DB B8 20 52 7D 1D 15 friendlyName: 1310000000008139 Remote MintChip Client (Developer Challenge) subject=/CN=1310000000008139/OU=Remote MintChip Client/O=Royal Canadian Mint/C=CA issuer=/CN=Remote MintChip Certificate Authority/OU=Remote MintChip/O=Royal Canadian Mint/C=CA -----BEGIN CERTIFICATE----- ... -----END CERTIFICATE----- Certificate bag Bag Attributes friendlyName: Remote MintChip CA (Developer Challenge) subject=/CN=Remote MintChip Certificate Authority/OU=Remote MintChip/O=Royal Canadian Mint/C=CA issuer=/CN=Remote MintChip Certificate Authority/OU=Remote MintChip/O=Royal Canadian Mint/C=CA -----BEGIN CERTIFICATE----- ... -----END CERTIFICATE-----
The Private Key
As far as I can tell there is nothing noteworthy about the private key.
The Client Authentication Certificate
Inspecting the first of the two certificates yields:
$ echo "$FIRST_CERT" | openssl x509 -noout -text Certificate: Data: Version: 3 (0x2) Serial Number: 1198 (0x4ae) Signature Algorithm: sha1WithRSAEncryption Issuer: CN=Remote MintChip Certificate Authority, OU=Remote MintChip, O=Royal Canadian Mint, C=CA Validity Not Before: Mar 6 10:06:45 2012 GMT Not After : Mar 7 10:06:45 2013 GMT Subject: CN=1310000000008139, OU=Remote MintChip Client, O=Royal Canadian Mint, C=CA Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public Key: (1024 bit) Modulus (1024 bit): 00:a7:1b:d9:81:17:ce:ae:b7:e8:46:6c:51:6b:b8: ... 62:20:0b:93:f7:02:4c:c5:dd Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Basic Constraints: CA:FALSE X509v3 Key Usage: Digital Signature X509v3 Extended Key Usage: TLS Web Client Authentication Signature Algorithm: sha1WithRSAEncryption 67:b9:d1:47:c2:62:82:60:1d:f9:01:04:de:c6:db:19:f3:3e: ... 17:16:60:0f
As can be seen by the "Extended Key Usage" extension, this certificate will be used for client-side certificate authentication.
I think this is pretty cool. When password protected, client-side certificates provide a nifty and unobtrusive form of two-factor authentication. I've only ever seen them used "in the wild" by CACert, so it's fun to see someone else using them.
As before, this certificate is signed by the "Remote MintChip Certificate Authority".
Nothing else is particularly surprising.
The MintChip hosted API uses SSL client certificates for authentication, and both client and server certificates are signed by MintChip's own self-signed certificate authority.