I have a Javascript that is signing a text string in the browser. It uses CAPICOM under Internet Explorer and window.crypto under Mozilla browsers. After the signing process I receive a BASE64 encoded signature.
Using HTTPS I upload the signature and the text string to a webserver with a PHP application. From the SSL (HTTPS) I receive the user’s certificate. From this certificate I can extract the user’s Public Key.
Now I want to verify that the signature against the signed text string and the user’s certificate and public key. I have tried with openssl_verify PHP function with no success.
I always receive an error:
error:0408D077:rsa routines:FIPS_RSA_VERIFY:wrong signature length
- I have the certificate and it is OK;
- I have the public key extracted from the certificate and it is also verified and OK;
- I have the signature (BASE64 decoded);
Unfortunately I can’t verify the signature? I can’t provide a demo or sample because it is only in the local network at the moment.
OK, finally I have found a workaround.
window.crypto. For more information read thisBoth –
window.cryptoand CAPICOM are not very well documented for web using (CAPICOM is not only for web!)Now the problems:
openssl_verify()function of PHP is also not well documented and always returns zero – signature not valid.So what is the workaround:
signText()function expects a third parameter which must be the trusted Certificate Authority names. First I expected that this must be the CN of the issuer of the client’s certificate. But actually it is not. It must be all the issuer string separated with comas like:"C=Country,ST=State,L=Location,O=Organization,CN=CommonName,STREET=Address"Unfortunately this string is slightly different from the issuer string from openssl which looks likeissuer=/streetAddress=Address/CN=CommonName/O=Organization/L=Location/ST=State/C=Country. If someone have a Firefox under Linux it will be very interesting to check if this string is formatted the same way. I don’t know how to separate more CA names in a single string.Now. What my source code looks like:
window.crypto(I receive an additional parameter from the webbrowser how the signature was generated) If CAPICOM is used I convert the source data like this:$_POST['source'] = iconv('UTF-8', 'UTF-16LE', $_POST['source'])"-----BEGIN PKCS7-----\n".$_POST['signature']."\n-----END PKSC7-----"Note that the header and footer must be on separate lines. The lines separator must be only \n (ASCII #10) not \r (ASCII #13) of \r\n (ASCII #13#10).smime– to use the SMIME function of the CMD tool-verify– to do a verification-in filepath– the path to the signature file created in step 4-inform PEM– the forat of the signature is BASE64 encoded file with header and footer-binary– prevents translation of the source from binary to text-content filepath– the path to the source file created in step 3-CAfile filepath– the path to the trusted CA root certificates file created in step 5So the final command looks like this:
openssl smime -verify -in file.pem -inform PEM -binary -content source.txt -CAfile root.pemVerification successful– the signature is OKVerification failure– the signature is not OKThe above works for me. Unfortunately openssl, CAPICOM and
window.cryptoare very tricky and it is always possible that a problem occurs. Hope this will help somebody.Best Regards