Certificate patcher program description.

Please note: ca-fix is no longer needed in all but the oldest versions of OpenSSL or SSLeay  (earlier than 0.9.2) this is because it is no longer needed: V3 extensions can now be added with the satandard utilities, ca, x509 and req. Check out the file doc/openssl.txt for more information.

As a result most of this information is no longer relevant but it is retained for historical reasons...

The program ca-fix is a certificate patching program. It was originally designed to patch SSLeay generated V1 CA certificates but it can be used to patch end user certificates as well and as a test utility.

You can download version (0.41) of the program here.

The only changed from 0.4 is that the setkey option is now supported. The code got accidentally removed in the last version.

The original motivation was to allow SSLeay V1 CA certificates to be properly recognized as CA certificates by Netscape. For more details of why this is a good idea see: Netscape CA handling: When is a CA Not a CA?

Compiling the program.

For most Unix systems you should just need to edit the Makefile and type make. For Windows you will need Visual C++ and you need to compile the program as a normal SSLeay program. This means including the SSLeay include and library directories and linking the result with ssleay32.lib. Be sure to set the runtime library to multithreaded DLL (under code generation) or the program will not work properly (it will most likely crash).

Program Usage.

-in cert.pem      input certificate.
-out cert.pem     output certificate.
-caset            set cA flag, add basic constraints
-caunset          don't set cA flag, add basic constraints
-caclr            delete basic constraints
-pathlen n        set path length to 'n'
-bscrit           make basic constraints critical
-nscrit           make nscertype critical (not recommended)
-nscertype num    set nscertype to num
-nsclr            delete nscertype
-inkey pkey.pem   private key of signer
-nosign                         don't sign the certificate.
-noout                          don't output certificate.
-print                            print the certificate in text form.

E.g. for a typical CA:

ca-fix -in cacert.pem -inkey pkey.pem -caset -nscertype 6 -out newca.pem

Most of the arguments should be self explanatory. A few need further explanation.

With inkey you must sign with the issuers private key or the certificate signature will fail. For the usual self signed CA this is the certificates own private key. For other kinds it is the private key of the issuing CA.

The pathlen parameter specifies the maximum CA chain length. For example if this is set to zero then any certificates signed by this CA cannot themselves be CA certificates. Setting this to one would allow this CA to sign subordinate CA certificates but the subordinate CAs would not be allowed to sign CA certificates. If the software you are using interprets this parameter correctly then it allows some control over what subordinate CAs are allowed to do.

The bscrit option sets the critical flag for basic constraints: it is not set by default. Basic constraints is a standard certificate extension it should be interpreted correctly by any reasonable software: making this extension to critical is acceptable (and advisable). Unfortunately Microsoft Outlook 98 chokes on critical extensions so its now off by default.

The nscrit flag sets the critical flag of netscape-certificate-type. It is strongly recommended that this option is not used because any implementation that does not interpret this non standard extension will reject the certificate as invalid. For example Outlook 98 does this. If you don't mind or want this behaviour then feel free to use the option...

Try using the verify program on the new certificate after using the program to check the signature.

You can also use this program to mess around with user certificates to e.g. change the value of nsCertType. Naturally you should use the issuing CAs private key to sign the certificate.

Here are the currently used values for nsCertType or netscape-certificate-type: number may be decimal or hex with the 0x prefix. Add together the options you need.
Value Meaning
0x80 SSL client authentication.
0x40 SSL server
0x20 S/MIME mail.
0x10 Object signing.
0x04 SSL Client CA.
0x02 S/MIME CA.
0x01 Object Signing CA.

The extension is only really mandatory for object signing certificates (and CAs according to the documentation but this is not enforced). It is also useful if you want to restrict the uses of a certificate.

If you check the Netscape documentation you will find that the above values seem to be wrong. They aren't: it's just due to the way the BIT STRINGS work. You need to reverse the order of the bits of each byte.

In actual fact the above value for nsCertType are those specified in the Netscape documentation. Netscape Communicator for example is somewhat more "generous" in its interpretation, for example it will allow certificates without the S/MIME bit set to be used for S/MIME. Check my document Netscape Certificate Type Behaviour  for a fuller description of how Netscape Communicator actually interprets this extension. If in doubt check to see if the restrictions you place on a certificate are actually enforced.

Advanced Options.

Warning: if you don't have a pretty good knowledge of certificate structure and related issues then you should probably skip this section. You'll probably never need to use any of these options. They are strictly "hackers only".

Firstly a bit of backround. ca-fix was originally intended just to fix up CA certificates. I found though that I would occasionally come across a certificate with unusual behaviour and I wanted to track down the cause.

You can't just use someone elses certificate because you don't know the private key. Similarly you can't just paste in you own public key because that would break the signature.

Similarly I wanted a way to delete and add various certificate extensions to see what they did.

Add all these requirements together and you get the advanced options.

Here is a list of these options followed by a brief explanation.

-setkey           change certificate public key to match signer
-delext ext       delete extension (can use OID)
-ext genopt  val  add several extensions
-Cext genopt val  add several critical extensions
genopt can be:    keyUsage, nsCertType, nsBaseUrl, nsRevocationUrl,
                  nsCaRevocationUrl, nsRenewalUrl, nsCaPolicyUrl,
                  nsSslServerName, nsComment
-rawext opt HEX   add raw extension (can use OID)
-Crawext opt HEX  add critical raw extension (can use OID)
-rawfile opt fn   add raw extension from file.
-Crawfile opt fn  add critical raw extension from file.
-extusage OID     add extended key usage OID (can be used more than once).
-extcrit          make extended key usage critical.
-extparse         ASN1 parse extensions.
-exthex           hexdump extensions.

To see why setkey is useful suppose you have two certificates ca.pem (a root CA certificate) and user.pem (an end user certificate) which do something odd. You can't use them directly but you can use two almost identical certificates for diagnostic purposes. Firstly you would create two privake key files (with, for example, genrsa -out key.pem 1024) call these cakey.pem and userkey.pem.

First you need to set the ca public key and resign the certificate:

ca-fix -in ca.pem -setkey -inkey cakey.pem -out myca.pem

The CA public key now matches the generated key in cakey.pem.

Now you need to do the same with the end user certificate:

ca-fix -in user.pem -setkey -inkey userkey.pem -out usertmp.pem -nosign

Finally you need to sign the new user certificate with the CA key, since you have already set the public key you don't use the setkey option here:
ca-fix -in usertmp.pem -inkey cakey.pem -out myuser.pem

You would then want to check it worked using verify:

verify myca.pem
verify -CAfile myca.pem myuser.pem

You can now use the certificates because you have the referenced private keys. You should note this is not a security problem because you can't just forge the use of these certificates in a trusted environment because the keys have changed. Its only useful for test and diagnostic purposes.

Now suppose these new certificates exhibit the same unusual behaviour. Maybe it's caused by some weird extension? That's where the delext option comes in. Suppose you suspect an extension with OID then you can delete it with:

ca-fix -in myuser.pem -out myuser2.pem -delext -inkey cakey.pem

A note about the ext and Cext options. Using these you can set the standard extensions keyUsage, nsCertType, nsBaseUrl, nsRevocationUrl, nsCaRevocationUrl, nsRenewalUrl, nsCaPolicyUrl, nsSslServerName, nsComment.

keyUsage is a standard extension referenced in, for example the PKIX documentation. The others are Netscape specific extensions that are described here, it also describes how Netscape products handle keyUsage. keyUsage and nsCertType both take an integer argument (with 0x prefix for hex) all the others take a string argument. As is usual with integer BIT STRING arguments you should reverse the bit order of each byte.

Finally the really advanced options: rawext and Crawext. These allow you to add any extension you want, but unfortunately you need to give it the full DER encoding of the extension. Suppose for example you saw a certificate with an extension with OID and its contents were: 30030101FF (in hex). You could do this with:

ca-fix -in myca.pem -out myca2.pem -rawext 30030101FF -inkey cakey.pem

This isn't the best example in the world because it's just basic constraints which you can more easily add with just the caset option.

The rawfile and Crawfile do the same but take extensions from a file.

The extparse option gives and ASN1 dump of the certificate extensions. To use it try:

ca-fix -in cert.pem -nosign -noout -extparse

The exthex option is similar except it gives a hex dump of the extensions. This make it possible to use the output in a rawext or Crawext option.

This can be used to print out a hex dump of an extension which can then be used to add the DER encoding of the extension manually in another product (e.g. NS certificate server). For example if you want the DER encoding of basicConstraints with a path length of 10:

ca-fix -in cert.pem -nosign -caset -pathlen 10 -exthex

will print it out.

All comments see my contact page.