Showing posts with label certificate. Show all posts
Showing posts with label certificate. Show all posts

Thursday, July 4, 2013

Replacing self-signed expired certificates using OpenSSL tool

I just realized that one of the certificates I use was expired and OpenVPN didn't want to connect to a server for that reason. So, it was time to generate new certificate/key pair. That's easy, using CA.pl script, part of openssl-perl package. Just do the following sequence of steps:
./CA.pl -newreq-nodes./CA.pl -sign
But the second command didn't work and I was getting the following error messsage:
Sign the certificate? [y/n]:y
failed to update database
TXT_DB error number 2
Signed certificate is in newcert.pem
Quick search revealed that I'm trying to issue new certificate that has the same name as the existing one, even though the existing one was expired. There are multiple solutions to this, as documented in the comment of the blog post I found. But the real solution is to revoke expired certificate, and then to sign a new one (note that you don't have to generate another CSR):
ca -config openssl.cnf -revoke oldcert.crt -keyfile cakey.pem -cert cacert.pem
Note that the revocation doesn't mean you have to have OCSP or CSR. Now, old certificate is revoked and you can sign a new one.

Thursday, January 3, 2013

Signing XML document using xmlsec1 command line tool

Suppose that you have some XML document you wish to sign. It turns out it's very easy to do so because there is xmlsec library, and in particular xmlsec1 command line tool that's standard part of Fedora Linux distribution. The only problem is that its very picky and not very informative when it comes to error logging, finally, there are a lot of small details that can catch you. Since I had to sign a document I spent some time trying to figure out how to do that. In the end, I managed to do it and I'll write here how to for a future reference. Before I continue you'll need certificate and a key to be used for verification and signing. They are not the topic of this post so I'll just give you them: private key, certificate, and CA certificate.

Ok, let's assume that you have the following XML document you wish to sign:
<?xml version="1.0" encoding="UTF-8"?>
<document>
  <firstelement attr1="attr1">
    Content of first element.
    <secondelement attr2="attr2">
      Content of the second element.
      <thirdelement attr3="attr3">
        And the content of the third element.
      </thirdelement>
    </secondelement>
  </firstelement>
</document>
Basically, you can take any XML document you wish. I'll suppose that this XML document is stored in the file tosign.xml. If you typed yourself XML document, or if you just want to be sure, you can check if XML is well formed. There is xmllint tool that surves that purpose. Just run it like this:
$ xmllint tosign.xml
And if you don't get any error messages, or warnings, that the XML document is well formed. You can also check if the document is valid by providing schema, or DTD, via appropriate command line switches.

In order to sign this document you have to add XML Signature fragment to the XML file. That fragment defines how the document will be signed, what will be signed, and, where the signature, along with certificate, will be placed. The fragment has the following form:
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
  <SignedInfo>
    <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
    <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
    <Reference>
      <Transforms>
        <Transform           Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
        <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
      </Transforms>
      <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
      <DigestValue />
    </Reference>
    </SignedInfo>
  <SignatureValue />
  <KeyInfo>
    <X509Data />
  </KeyInfo>
</Signature>
Note that this (quite verbose) fragment has to be placed somewhere within the root element. Now, lets sign this, newly created document. To do so invoke xmlsec1 command like this (this is one line in case it is broken into two due to the formatting):
xmlsec1 --sign --privkey-pem privkey.pem,cert.pem --output signed.xml tosign.xml
After this, the signed XML document will be in the file named signed.xml. Take a look into it, the placeholders within signature fragment are filled up with signature data, and with a certificate who's private key was used to sign the XML document.

Note that signature itself is generated using private key (privkey.pem) which, as its name suggest, has to be private for a signer. Otherwise, anyone can falsify signature.

Now, to verify signed XML document you have to specify trusted CA that will be used to verify signature. It has to be certificate of the certificate authority (CA) that issued signer's certificate. In my case that's cacert.pem, i.e.:
$ xmlsec1 --verify --trusted-pem cacert.pem signed.xml
OK
SignedInfo References (ok/all): 1/1
Manifests References (ok/all): 0/0
As you can see, the signature was verified OK. You can try now to change something in the XML document and see if the verification passes or not.

I'll mentioned one more thing before concluding this post. Namely, in the previous example the whole XML document was signed. But, you can sign only a part. To do so, you have to do two things. The first one is to mark the element that you wish to sign (its content will also be signed) and the second is to tell xmlsec1 to sign only that element.

The first step is accomplished by adding attribute to the element that should be signed. Let's assume that in our case we only want secondelement to be signed. Modify the appropriate opening tag to have the following form:
<secondelement attr2="attr2" id="signonlythis">
Note that I added attribute id, but basically any name can be used (unless you use some predefined schema or DTD).

The second step is to tell xmlsec1 that only this element should be signed. This is accomplished by modifying Reference element to have the following form:
<Reference URI="#signonlythis">
If you now try to sign this modified XML document using command I gave above, you'll receive an error message:
$ xmlsec1 --sign --privkey-pem cert.key,cert.pem --output test_signed.xml tosign.xml
func=xmlSecXPathDataExecute:file=xpath.c:line=273:obj=unknown:subj=xmlXPtrEval:error=5:libxml2 library function failed:expr=xpointer(id('signonlythiselement'))
func=xmlSecXPathDataListExecute:file=xpath.c:line=356:obj=unknown:subj=xmlSecXPathDataExecute:error=1:xmlsec library function failed:
func=xmlSecTransformXPathExecute:file=xpath.c:line=466:obj=xpointer:subj=xmlSecXPathDataExecute:error=1:xmlsec library function failed:
func=xmlSecTransformDefaultPushXml:file=transforms.c:line=2405:obj=xpointer:subj=xmlSecTransformExecute:error=1:xmlsec library function failed:
func=xmlSecTransformCtxXmlExecute:file=transforms.c:line=1236:obj=unknown:subj=xmlSecTransformPushXml:error=1:xmlsec library function failed:transform=xpointer
func=xmlSecTransformCtxExecute:file=transforms.c:line=1296:obj=unknown:subj=xmlSecTransformCtxXmlExecute:error=1:xmlsec library function failed:
func=xmlSecDSigReferenceCtxProcessNode:file=xmldsig.c:line=1571:obj=unknown:subj=xmlSecTransformCtxExecute:error=1:xmlsec library function failed:
func=xmlSecDSigCtxProcessSignedInfoNode:file=xmldsig.c:line=804:obj=unknown:subj=xmlSecDSigReferenceCtxProcessNode:error=1:xmlsec library function failed:node=Reference
func=xmlSecDSigCtxProcessSignatureNode:file=xmldsig.c:line=547:obj=unknown:subj=xmlSecDSigCtxProcessSignedInfoNode:error=1:xmlsec library function failed:
func=xmlSecDSigCtxSign:file=xmldsig.c:line=303:obj=unknown:subj=xmlSecDSigCtxSigantureProcessNode:error=1:xmlsec library function failed:
Error: signature failed
Error: failed to sign file "tosign.xml"
The problem is that URI attribute references ID attribute of an element. But, ID element isn't recognized by name but has to be specified in DTD or in schema, depending what you have. In our case there is neither schema nor DTD and thus ID isn't recognized by xmlsec1. So, we have to tell it what is the name of the ID attribute, and that can be done in two ways. The first one is by using command line switch --id-attr, and so the command to sign this document is:
xmlsec1 --sign --privkey-pem privkey.pem,cert.pem --id-attr:id secondelement --output signed.xml tosign.xml
The name after the column is the attribute name that is ID. Default value is "id", but can be anything else. If it is "id", then it can be omitted. The argument to --id-attr is element whose attribute should be treated as an id. You should also be careful of namespaces. If they are used then the namespace of the element has to be specified too, and not shorthand but the full namespace name. Finally, note that XML is case sensitive!

The other possibility is to create DTD file and to give it as an argument to xmlsec1. In this case, DTD should look like this (I'll assume that this is the content of a file tosign.dtd):
<!ATTLIST secondelement id ID #IMPLIED>
And you would invoke xmlsec1 like this:
xmlsec1 --sign --privkey-pem privkey.pem,cert.pem --dtd-file tosign.dtd --output signed.xml tosign.xml
Note that you'll receive a lot of warnings (DTD is incomplete) but the file will be signed. To check the signature, you again have to specify either --dtd-file or --id-attr options, e.g.
xmlsec1 --verify --trusted-pem cacert.pem --id-attr:id secondelement signed.xml
Now, you can experiment to check that really only secondelement was signed and nothing else.

Final note. You have to put XML signature fragment in XML file you are signing. What can confuse you (and confused me) is that there is an option sign-tmpl that adds this fragment, but it is very specific and used only for testing purposes.

Thursday, November 8, 2012

Installing certificate for Alfresco...

This post is continuation of the post about installing Alfresco using native Tomcat6 installation (on CentOS6). If you followed steps given in that post, you have running Alfresco installation but Tomcat uses self-signed certificate.

To install your own certificate first obtain it (you can use your own, self managed, CA or you can buy commercial one), then install it on your Tomcat instance. You'll find a lot of information about this in SSL Howto on Tomcat's Web pages, but that page assumes that everything you do, you are doing using keytool.

Here is a quick Howto with an assumption that you have files newcert.pem (containing certificate), newkey.pem (containing private key) and cacert.pem (your CA certificate). By default, tomcat's keystore is in its home (/usr/share/tomcat6) and it is named .keystore. Keystore file is password protected and default password for it is changeit. Note that the period isn't part of password! I suggest that you copy this file to root's home under the name keystore (note no leading dot!) or whatever else you wish so that you can restore old copy in case something goes wrong with the following steps.

The installation is two step process. First, you create keystore containing you certificate, private key and CA's certificate. In second step, you import that information to Tomcat's keystore.

First step is to pack certificate for Alfresco, its private key and CA's certificate into PKCS12 store using openssl tool as follows:
$ openssl pkcs12 -export \
        -in newcert.pem -inkey newkey.pem \
        -out mycert.p12 -name tomcat \
        -CAfile cacert.pem -caname root -chain
Enter Export Password:
Verifying - Enter Export Password:
This command assumes that all necessary files (newcert.pem, newkey.pem and cacert.pem) are in you current directory. Output of the command is also stored into current directory. Note that you are asked for password that will protect all the data. Enter something or later you'll see the following warning:
*****************  WARNING WARNING WARNING  *****************
* The integrity of the information stored in the srckeystore*
* has NOT been verified!  In order to verify its integrity, *
* you must provide the srckeystore password.                *
*****************  WARNING WARNING WARNING  *****************
And then you'll receive the following error:
keytool error: java.security.UnrecoverableKeyException: Get Key failed: / by zero
Second step is to import this pkcs12 file to tomcat's keystore using keytool as follows:
$ keytool -importkeystore -srckeystore mycert.p12 \
        -srcstoretype pkcs12 -destkeystore /usr/share/tomcat6/.keystore
Enter destination keystore password:
Enter source keystore password:
Existing entry alias tomcat exists, overwrite? [no]:  yes
Entry for alias tomcat successfully imported.
Import command completed:  1 entries successfully imported, 0 entries failed or cancelled
Again, input file is in the current directory and you are importing directly into tomcat's keystore. Note that the existing certificate with the alias tomcat will be removed and you are asked to confirm that! The default alias Tomcat searches when it start is called tomcat.

Third step is to change private key's password that has to be the same as for the keystore. Do that using the following command:
keytool -keypasswd -alias tomcat -new <keypassword> -keystore /usr/share/tomcat6/.keystore
You'll be asked for the keystore's password and the password for the key will be set to keypassword.

And that's it. Restart tomcat and check if it is using new certificate.

Thursday, September 1, 2011

CAs are broken... but... there may be a fix...

Everyone by now heard of security breach of DigiNotar. The Internet is full of stories about it! I won't go into details what happened. Instead, I'll try to pinpoint what actual problem is, and, based on that, I'll try to outline possible solution.

Let us start with the problem. The problem is that every single CA is actually single point of failure of the whole distributed system. Do you need fraudulent Google certificate? No problem, attack the weakest CA you can find, or try to attack more of them, and there you go.  Now, I can here you say: Remove weakest CA! Well, it's not so easy. Applying this rule recursively you'll end up with one, or no CAs at all. This is not a solution either. And this also adds another dimension to the problem, the less CAs the more fragile the Internet becomes because each CA is anyway highly likely target. And you know the main premise of security: You are never ever absolutely secure!

So, what is the solution? I believe that the solution is to keep the system as it is, but to introduce signatures from multiple CAs in a single certificate. This won't resolve the problem, but it will make life harder to hackers. Besides, absolute security doesn't exist, as I already mentioned.

From the implementation standpoint, it is possible to do this either by changing certificate structure, or to change implementations so that they can check multiple certificates. In case multiple certificates are used it's obviously necessary to have some common information that will allow all those certificates to be related.

Validity of certificate (or certificates) could be calculated probabilisticaly. Additionally,  some independent measure of correlation between CAs could be defined so that the validity of a single site that uses this system can be evaluated based on this correlation measure (meaning, the less correlated CAs signed the more valid it is).

Note that if a single CA goes into bankruptcy, or is removed from trusted CA list, doesn't mean that everyone has to issue a new certificate imediatelly.

I would say that CAs implemented this way would be somewhere between current CA system and PGP Web of Trust.

About Me

scientist, consultant, security specialist, networking guy, system administrator, philosopher ;)

Blog Archive