Problem verifying signature created with openssl generated key
[nobr]This is a long posting so please bear with me!
I am having problems verifying a signature created by an openssl generated key and certificate.
I created a private key and self signed certificate as described in http://developer.softwareag.com/tamino/documentation/ssl/ssl_support/certificates.htm
I then used the php script below to sign some text and write the signature to a file. The signature is then read back in and verified using the certificate.This works:
PHP Script
<?php
// The file the source data will be saved in
$sourceFile ="/tmp/SourceData.txt";
// Create the unencrypted text info and store it in a file
$source ="Some text to be signed\n";
file_put_contents($sourceFile, $source);
// Paths to private key and certificate generated by openssl
$privateKeyPath="/Projects/CreateKeys/server.key.unsecure";
$certPath ="/Projects/CreateKeys/server.crt";
// Read in the private key data
$fp=fopen($privateKeyPath,"r");
$priv_key_data=fread($fp,8192);
fclose($fp);
$priv_key = openssl_pkey_get_private($priv_key_data);
// Read in the source data from the file
$fp=fopen($sourceFile,"r");
$srcDataFromFile=fread($fp,8192);
fclose($fp);
// compute signature
$result = openssl_sign($srcDataFromFile, $signature, $priv_key);
if ($result == True)
{
print"<br>";
print"Signature created successfully:";
print"<br>";
// Write the signature to the output file base64 encoded
$sig = base64_encode($signature);
file_put_contents("/tmp/signature.txt", $sig);
}
else
{
print"<br>Failed to sign<br>";
}
// Now try to verify signature
$fp=fopen($certPath,"r");
$cert_data=fread($fp,8192);
fclose($fp);
$pub_key = openssl_get_publickey($cert_data);
$cert_res = openssl_x509_read($cert_data);
$keyCheck = openssl_x509_check_private_key($cert_res, $priv_key);
if ($keyCheck == True)
{
$result = openssl_verify($srcDataFromFile, $signature, $pub_key);
if ($result == True)
{
print"<br><br>";
print"Signature verified";
print"<br><br>";
}
}
openssl_free_key($pub_key);
openssl_x509_free($cert_res);
?>
Now we get to the Java code.
All I want to do here is to verify the signature created by the PHP code using the same certificate I used to verify the signature in PHP:
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
publicclass SignatureTest
{
publicstaticvoid main(String[] unused)throws Exception
{
// Get the public key from the certificate
Certificate cert = readCertificateFromFile();
PublicKey publicKey = ((X509Certificate)cert).getPublicKey();
byte[] sigbytes = getSignatureBytes("C:/tmp/signature.txt");
boolean result = verify("C:/tmp/sourceData.txt", publicKey,"MD5withRSA", sigbytes);
System.out.println("Signature Verification Result = " + result);
}
privatestatic Certificate readCertificateFromFile()
{
Certificate cert =null;
try
{
FileInputStream fis =new FileInputStream("C:/Projects/CreateKeys/server.pem");
BufferedInputStream bis =new BufferedInputStream(fis);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
while (bis.available() > 0)
{
cert = cf.generateCertificate(bis);
System.out.println(cert.toString());
}
}
catch (Exception e)
{
System.out.println("ERROR: " + e);
e.printStackTrace();
}
return cert;
}
publicstaticbyte[] getSignatureBytes(String filename)
{
byte[] sigBytes =null;
try
{
FileInputStream in =new FileInputStream(filename);
sigBytes =newbyte[8192];
int count = in.read(sigBytes);
in.close();
}
catch (Exception e)
{
System.out.println(e.toString());
e.printStackTrace();
}
return sigBytes;
}
}
Which produces the result:
Signature Verification Result = false
Please can someone help? I have spent several days trying to sort out this problem.
Thanks in advance...[/nobr]
[8049 byte] By [
rdhulla] at [2007-10-3 3:19:14]

Thank you both for responding so quickly - it is much appreciated!
The verify method is as below:
private static boolean verify(String datafile, PublicKey pubKey, String sigAlg, byte[] sigbytes) throws Exception
{
Signature sig = Signature.getInstance(sigAlg);
sig.initVerify(pubKey);
FileInputStream fis = new FileInputStream(datafile);
byte[] dataBytes = new byte[8192];
int nread = fis.read(dataBytes);
while (nread > 0)
{
sig.update(dataBytes, 0, nread);
nread = fis.read(dataBytes);
}
return sig.verify(sigbytes);
}
I have taken on board the point about the signature and have modified the method as suggested. I have also removed the while (bis.available() > 0) test which served no purpose.
After reading the PHP openssl_sign documentation again the signing algorithm used is SHA1 not MD5 so I modified the algorithm passed to the verify method to be SHA1withRSA.
Unfortunately the results are still the same. The strange thing is that the PHP code signs and verifies the data without problem. It is only when I try to verify the signed data in Java there is a problem.
Another point to note is that the self signed certificate server.crt file generated by the openssl commands was as follows:
Certificate:
Data:
Version: 1 (0x0)
Serial Number: 1 (0x1)
Signature Algorithm: md5WithRSAEncryption
Issuer: C=UK, L=town, CN=CA/emailAddress=ca@ca.com
Validity
Not Before: Aug 23 19:03:24 2006 GMT
Not After : Aug 23 19:03:24 2007 GMT
Subject: C=UK, CN=name/emailAddress=name@company.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public Key: (1024 bit)
Modulus (1024 bit):
00:ea:4c:e7:ce:37:03:32:46:96:76:67:88:25:06:
c4:f5:1d:34:e8:47:4c:2b:6e:fd:ea:55:f6:42:29:
11:a4:e8:da:36:fa:16:17:ce:c8:5a:2e:b4:c6:f8:
bc:f2:7b:9a:b5:84:81:a9:8e:e4:1a:4f:94:bc:69:
86:1a:e6:a7:0c:95:2c:bc:13:42:57:d2:7c:c4:bc:
3a:d4:39:1c:91:29:02:01:0e:19:64:1e:af:d7:aa:
84:a3:64:c2:9f:20:88:fd:e7:95:78:a9:64:f6:c6:
d6:27:31:c7:c0:65:3a:11:a9:71:57:63:6e:bd:42:
9a:db:e1:45:c7:3b:ca:4b:e3
Exponent: 65537 (0x10001)
Signature Algorithm: md5WithRSAEncryption
b4:0c:03:bb:27:8b:5c:dc:67:c9:05:8f:67:3c:fb:6b:12:cd:
b5:7e:12:ec:d1:cc:5b:6c:15:24:8f:e6:8e:76:5d:79:13:ba:
7a:5a:20:2a:f3:32:bd:86:c0:87:c7:e2:dd:0b:d8:90:10:8e:
c0:b7:7e:b3:77:76:d2:bf:cb:14:d5:3d:72:0e:b4:d3:0d:2b:
a6:a4:f4:3b:ec:8b:ce:43:c0:d1:7e:e5:66:65:68:bf:db:6d:
fd:5a:2f:b3:56:10:06:9e:a5:be:d1:fd:d2:c2:6b:74:c7:ab:
4b:6c:6d:d9:47:1a:66:f4:1a:5e:e2:28:16:90:69:16:e4:cc:
ae:17
--BEGIN CERTIFICATE--
MIIB7zCCAVgCAQEwDQYJKoZIhvcNAQEEBQAwQzELMAkGA1UEBhMCVUsxDTALBgNV
BAcTBHRvd24xCzAJBgNVBAMTAkNBMRgwFgYJKoZIhvcNAQkBFgljYUBjYS5jb20w
HhcNMDYwODIzMTkwMzI0WhcNMDcwODIzMTkwMzI0WjA9MQswCQYDVQQGEwJVSzEN
MAsGA1UEAxMEbmFtZTEfMB0GCSqGSIb3DQEJARYQbmFtZUBjb21wYW55LmNvbTCB
nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA6kznzjcDMkaWdmeIJQbE9R006EdM
K2796lX2QikRpOjaNvoWF87IWi60xvi88nuatYSBqY7kGk+UvGmGGuanDJUsvBNC
V9J8xLw61DkckSkCAQ4ZZB6v16qEo2TCnyCI/eeVeKlk9sbWJzHHwGU6EalxV2Nu
vUKa2+FFxzvKS+MCAwEAATANBgkqhkiG9w0BAQQFAAOBgQC0DAO7J4tc3GfJBY9n
PPtrEs21fhLs0cxbbBUkj+aOdl15E7p6WiAq8zK9hsCHx+LdC9iQEI7At36zd3bS
v8sU1T1yDrTTDSumpPQ77IvOQ8DRfuVmZWi/2239Wi+zVhAGnqW+0f3Swmt0x6tL
bG3ZRxpm9Bpe4igWkGkW5MyuFw==
--END CERTIFICATE--
Now when I tried to use this as the certificate in the Java program I got the following exception:
java.security.cert.CertificateException: Unable to initialize, java.io.IOException: insufficient data
By snipping off everything above the --BEGIN CERTIFICATE--
line the exceptions stopped but the verify method still returned false.
If it is of any use the method I used to generate the self signed certificate and private key was as follows:
In a clean directory create a new directory called newcerts
Begin by creating a certificate sign request
openssl genrsa -des3 -out server.key 1024
Create a decrypted PEM version of the RSA private key
openssl rsa -in server.key -out server.key.unsecure
Create a certificate sign request with the RSA key
openssl req -new -key server.key -out server.csr -config new_openssl.cnf
The next part relates to the certificate authority:
Create an RSA private key for the root certificate
openssl genrsa -des3 -out ca.key 1024
Create a decrypted PEM version of this private key
openssl rsa -in ca.key -out ca.key.unsecure
Create an empty file called index.txt
Create a file called serial in the current directory and enter "01" in column 1, line 1
Create the self-signed root certificate with the private key using the following info:
openssl req -new -x509 -days 365 -key ca.key -out ca.crt -config new_openssl.cnf
Sign the original certificate with the newly created self-signed root certificate
This step creates the files server.crt, server.key and server.key.unsecure
openssl ca -config new_openssl.cnf -policy policy_any -out server.crt -infiles server.csr
I have tried creating keys with PHP openssl functions, Java JCE methods, keytool etc. and they all fail for one reason or another regardless of the signing algorithm (I've tried DSA as well as RSA).
Any further help would be really appreciated.