Verify certificate using Bouncycastle (J2ME)
Good evening. I have a problem.. I'm trying to verify certificate but signatures doesn't match!!!
byte[] cert_decoded = Base64.decode(pem_cert);
ASN1InputStream ais = new ASN1InputStream(cert_decoded);
DERObject obj = ais.readObject();
ASN1Sequence seq = (ASN1Sequence)obj;
ais.close();
X509CertificateStructure cert = new X509CertificateStructure(seq);
// getting certificate signature
byte[] signature = cert.getSignature().getBytes();
// trying to get "to be signed" structure
TBSCertificateStructure tbs = cert.getTBSCertificate();
// is it correct? trying to get bytes array of TBS..
byte[] tbs_byte = tbs.getEncoded();
RSAEngine engine = new RSAEngine();
// Is it correct? Cert uses "RSAwithSHA1"..
SHA1Digest digest = new SHA1Digest();
// Public key i'v got before from signing CA cert...
PSSSigner signer = new PSSSigner(engine, digest, 0);
signer.init(false, pub);
signer.update(tbs_byte, 0, tbs_byte.length);
boolean istrue = signer.verifySignature(signature);
In all cases i'm getting FALSE 8( what's wrong, please help! 8(
I tried to sign TBS data using CA's private key but signatures doesn't match anyway...
[1270 byte] By [
nx_a] at [2007-10-2 19:13:34]

Have you tried just using a X509CertificateObject?
Right after creating your X509CertificateStructure, use that to create it.
X509CertificateObject co = new X509CertificateObject(cert);
co.verify(pub)
The cert variable is the X509CertificateStructure you created.
The pub variable needs to be a java.security.PublicKey class.
Thank you very much, but it seems that X509CertificateObject is not part of Bouncycastle Lightweight (J2ME edition). I'm using last release 1.32. Maybe it is part of Sun JCE..8(
nx_a at 2007-7-13 20:54:48 >

Ah, you're right. Its part of the org.bouncycastle.jce.provider package.Ive downloaded BC's lightweight crypto jar to try and figure this out.
May be problem is in encoding of TBS structure that I'm getting with
byte[] tbs_byte = tbs.getEncoded()?
If I'm not mistaken, PKIX standarts expect from TBS structure to be in DER encoding. TBSCertificateStructure.getEncoded() and TBSCertificateStructure.getDEREncoded() return equal byte arrays.
Is there some opportunity to solve this problem? May be I'm getting wrong with TBS structure, and I have to extract objects from it and build some special object? I dont know what I'm doing wrong.
nx_a at 2007-7-13 20:54:48 >

Looks like i've solved this problem.
I tried to decrypt cert signature, using certificate public key:
xxxxxxxxxxxxxxxxqVФK?#1040;4,ммЖџ%禸эл;Яр, where xxxxxx are 15 bytes (almost all is 0x0). Then I've got digest from TBS:
VФK?#1040;4,ммЖџ%禸эл;Яр. They are similar.
What are the 15 bytes header?
nx_a at 2007-7-13 20:54:48 >

This might have something to do with the fact that you've setyour salt size in PSSSigner to 0.Try setting it to digest.getDigestSize() instead.
I've tried different sizes of salt in PSSSigner().. I've also tried smth like 34 - 16 = 18 (34 bytes block for another certificate! There used MD5 for hashing instead of SHA1 from previous post. So, 34 (block size) - 16 (hash size) = 18 bytes). But in all cases, PSSSigner.verifySignature() returned FALSE.
So, i tried to "cheat" a bit. I decrypted signature, using PKCS1Encoding class (like described in crypto/test/RSATest.java) and CA's public key. I tried different certificates with different hashing alghoritms, signed by different CAs. Interesting, that every time hash was placed in the end of this array after some random for fist sight bytes.
nx_a at 2007-7-13 20:54:48 >

I found example code here: http://www-128.ibm.com/developerworks/library/j-midpds.html
Below is that code pieced together with some minor fixes (seems they
had outdated calls to verifySignature() and generateSignature()).
This program runs and returns true for me. Maybe this can
help you figure out what's going on with your code...
import java.math.BigInteger;
import java.security.SecureRandom;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.digests.SHA1Digest;
import org.bouncycastle.crypto.engines.RSAEngine;
import org.bouncycastle.crypto.generators.RSAKeyPairGenerator;
import org.bouncycastle.crypto.params.RSAKeyGenerationParameters;
import org.bouncycastle.crypto.params.RSAKeyParameters;
import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
import org.bouncycastle.crypto.signers.PSSSigner;
import org.bouncycastle.util.encoders.Base64;
public class RSASigBCLW {
private static BigInteger pubExp = new BigInteger("11", 16);
private static RSAPrivateCrtKeyParameters privKey;
private static RSAKeyParameters pubKey;
public static void main(String[] args) {
try {
_main(args);
} catch (Exception e) {
System.out.println("ERROR: " + e.getMessage());
}
}
/**
* @param args
*/
public static void _main(String[] args) throws Exception {
SecureRandom sr = new SecureRandom();
RSAKeyGenerationParameters RSAKeyGenPara = new RSAKeyGenerationParameters(
pubExp, sr, 1024, 80);
RSAKeyPairGenerator RSAKeyPairGen = new RSAKeyPairGenerator();
RSAKeyPairGen.init(RSAKeyGenPara);
AsymmetricCipherKeyPair keyPair = RSAKeyPairGen.generateKeyPair();
privKey = (RSAPrivateCrtKeyParameters) keyPair.getPrivate();
pubKey = (RSAKeyParameters) keyPair.getPublic();
String message = "this is a test message.";
String signature = getSignature(message);
boolean b = verify(message, signature, getMod(), getPubExp());
System.out.println("verify? =" + b);
}
// Public key specific parameter.
public static String getMod() throws Exception {
return (new String(Base64.encode(pubKey.getModulus().toByteArray())));
}
// General key parameter. pubExp is the same as pubKey.getExponent()
public static String getPubExp() throws Exception {
return (new String(Base64.encode(pubExp.toByteArray())));
}
static public String getSignature(String mesg) throws Exception {
SHA1Digest digEng = new SHA1Digest();
RSAEngine rsaEng = new RSAEngine();
PSSSigner signer = new PSSSigner(rsaEng, digEng, 64);
signer.init(true, privKey);
byte[] mbytes = mesg.getBytes();
signer.update(mbytes, 0, mbytes.length);
byte[] sig = signer.generateSignature();
String result = new String(Base64.encode(sig));
return result;
}
static public boolean verify(String mesg, String signature, String mod, String pubExp) {
BigInteger modulus = new BigInteger(Base64.decode(mod));
BigInteger exponent = new BigInteger(Base64.decode(pubExp));
SHA1Digest digEng = new SHA1Digest();
RSAEngine rsaEng = new RSAEngine();
RSAKeyParameters pubKey = new RSAKeyParameters(false, modulus, exponent);
PSSSigner signer = new PSSSigner(rsaEng, digEng, 64);
signer.init(false, pubKey);
byte[] mbytes = mesg.getBytes();
signer.update(mbytes, 0, mbytes.length);
boolean res = signer.verifySignature(Base64.decode(signature));
return res;
}
}
Thank you cdelikat, you helped me alot. This code works perfectly, but PSSSigner() can verify signatures made by itself, not for real certificates.Soon I'll post class (in someone interested) based on bouncycastle that works with real certificates like X509CertificateObject from
nx_a at 2007-7-13 20:54:48 >

That header is OID of hash, used in signature (rfc3279)! These OID's are described in PKCS#1. Huuh.. :)
nx_a at 2007-7-13 20:54:48 >

Hi nx_
I am a student of University of South Australia and currently I am working on a thesis in which i have to verify digital certificate on a mobile phone which it receive from server as bytes.
I am trying to use Bouncy Castle and I have been successfui in creating a certificate on j2se But how can I regenerate the certificate on mobile phone from bytres and verify its signature.
Can you post your code in which u r verifying the signature on mobile phone.
I will be grateful to you for your help
Looking forward to you reply
SUNNY
Hello i tried using the code below which was provided above but i get an
Uncaught exception java/lang/NoClassDefFoundError: org/bouncycastle/asn1/DERObject. error.
I use the netbeans obfuscator. can somebody please help
byte[] cert_decoded = Base64.decode(pem_cert);
ASN1InputStream ais = new ASN1InputStream(cert_decoded);
DERObject obj = ais.readObject();
ASN1Sequence seq = (ASN1Sequence)obj;
ais.close();
X509CertificateStructure cert = new X509CertificateStructure(seq);
// getting certificate signature
byte[] signature = cert.getSignature().getBytes();
// trying to get "to be signed" structure
TBSCertificateStructure tbs = cert.getTBSCertificate();
// is it correct? trying to get bytes array of TBS..
byte[] tbs_byte = tbs.getEncoded();
RSAEngine engine = new RSAEngine();
// Is it correct? Cert uses "RSAwithSHA1"..
SHA1Digest digest = new SHA1Digest();
// Public key i'v got before from signing CA cert...
PSSSigner signer = new PSSSigner(engine, digest, 0);
signer.init(false, pub);
signer.update(tbs_byte, 0, tbs_byte.length);
boolean istrue = signer.verifySignature(signature);
Can somebody please help.
princa at 2007-7-13 20:54:48 >

