2

I have generated key pair in a java card and return public key. I generate public key again in android app and then the CSR in android

 private byte[] CertReqGeneration()  throws Exception
 {
    if(publickeyobj==null)
        return null;

    String info = "CN=cn, OU=ou, O=o, C=cn, ST=city";
    X500Principal x500 = new X500Principal(info);

    X500Name x500name;
    x500name= X500Name.getInstance(x500.getEncoded());

    CertificationRequestInfo csrInfo = new CertificationRequestInfo(x500name, publickeyobj, new DERSet());

    ASN1EncodableVector v = new ASN1EncodableVector();
    v.add(csrInfo);
    ASN1ObjectIdentifier oid = new ASN1ObjectIdentifier("0.0");
    v.add(new DERSequence(oid));
    v.add(new DERBitString(new byte[] {}));
    byte[] encoded = new DERSequence(v).getEncoded();
    byte[] PKCS10= DataSignGeneration(encoded);

       byte[] encoded = Base64.encode(PKCS10);
      String base64=new String(encoded);
    return  base64;

}

but when I want to issue it in ca I get error asn1 bad tag value met 0x8009310b

It's my code for sign in applet:

  //sign
      Signature signature=Signature.getInstance(Signature.ALG_RSA_SHA_PKCS1,false);
      signature.init(thePrivateKey,Signature.MODE_SIGN);
      signLength=signature.sign(buffer,(short)(ISO7816.OFFSET_CDATA & 0xFF), inputlength, buffer, (short)(0));

this is a signed csr that my code generated

G1Xsg/fetpr1/RfbUzWmDqRqu2GvymoQwXUJS/tB36l1SAvrRyDtwCgVHB3ukYFSZJeavFISQ9+R4zD1qxjO6r/E2/3o9UfARm2GeTwEZFv8LVgULAPc/e64v5xkiQYO05QwHa5PtmaXXD4NtuSNvF9xgNjtdAkosKqEPLcme5k=
pedrofb
  • 37,271
  • 5
  • 94
  • 142
Fatemeh
  • 177
  • 15

3 Answers3

5

Let us take a look at your generated CSR first. I use an online ASN.1 decoder.

Well, the online tool won't decode your CSR. SO it is not valid:

enter image description here

Okay, let see what a valid CSR looks like. I generated a CSR using OpenSSL:

ghasemi@ghasemi-MS-7693:~$ openssl genrsa -out priv.key 1024
Generating RSA private key, 1024 bit long modulus
............................++++++
.......................++++++
e is 65537 (0x10001)
ghasemi@ghasemi-MS-7693:~$ ls
priv.key
ghasemi@ghasemi-MS-7693:~$ openssl req -new -key priv.key -out my_csr.csr
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:IR 
State or Province Name (full name) [Some-State]:Tehran
Locality Name (eg, city) []:Tehran
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Company
Organizational Unit Name (eg, section) []:Section
Common Name (e.g. server FQDN or YOUR name) []:Ebrahim
Email Address []:ebr.ghasemi at gmail 

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

ghasemi@ghasemi-MS-7693:~$ ls
my_csr.csr  priv.key

As you see above, I generated a CSR with a 1024 bit Key pair. Let see contents:

ghasemi@ghasemi-MS-7693:~$ cat my_csr.csr 
-----BEGIN CERTIFICATE REQUEST-----
MIIByzCCATQCAQAwgYoxCzAJBgNVBAYTAklSMQ8wDQYDVQQIDAZUZWhyYW4xDzAN
BgNVBAcMBlRlaHJhbjEQMA4GA1UECgwHQ29tcGFueTEQMA4GA1UECwwHU2VjdGlv
bjEQMA4GA1UEAwwHRWJyYWhpbTEjMCEGCSqGSIb3DQEJARYUZWJyLmdoYXNlbWkg
YXQgZ21haWwwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOJK2YUOSREjrDbZ
auC3/509NOAL+xjqJ2x947CtSIyuPSLuplDW4oAkvaqYvA5ocIxeAGbW9WZF/OdM
8z5XoQF3+ogGsEna1TZN1TY5XOdrRgIu9gFA2KRNPjnEZIkt7FLBJUQlk5aithk4
lfy73XCoosjWUwBOKac5ZIKOuXEHAgMBAAGgADANBgkqhkiG9w0BAQsFAAOBgQCF
hQzkAgfongzP9EKV+oTwVhqkQ7bfy5TE85YIR3aymuzbvAc9KWdWydOxHiHqXbmZ
ECWvLlMsrlrpyDO2Xxy8UXFJkNgH4Rys267ETaoYh19htc4qZzNqK/1ejQBUidgY
QoafJxv3YhO+gYr2txyxPRN0etcquElwx0odF8KBVA==
-----END CERTIFICATE REQUEST-----
ghasemi@ghasemi-MS-7693:~$ 

Well, the obvious different are the length and the start and end lines. My CSR is really bigger than yours. It starts with -----BEGIN CERTIFICATE REQUEST----- and end with -----END CERTIFICATE REQUEST----- too.

Let us check its contents with ASN.1 decoder:

enter image description here

Okay. As you see, there are the Characters that I entered during CSR generation inside the CSR in plain text, but not in yours.

So what's wrong?

Your applet, returns the Signature of your CSR Info only. It is not the CSR, It is the Signature of it only. So you must generate the CSR with the CSR info and the Signature. Moreover the public key used in the CSR Info MUST be the public key that its private key is used to generate the signature, otherwise the CA won't be able to verify the validity of CSR and it consider your CSR as a forged/fake csr.

So, after generation of KeyPair inside the card, export the public key to the android app. and then generate the CSR info and generate the signature of this info inside the card and then using the csr info and the signature build your CSR.

Ebrahim Ghasemi
  • 5,850
  • 10
  • 52
  • 113
  • Thank you. As you see in my code i did all thing as you told. I got public key from card and re generated public key in android. I think i should add csr + signature of csr (both of them) in asn1. Is itcorrect? – Fatemeh Oct 24 '16 at 09:34
3

@Abraham analysis seems correct: the generated CSR content is not valid

I guess the purpose of this code is building the ASN.1 structure to sign, but bouncycastle do it for you.

ASN1EncodableVector v = new ASN1EncodableVector();
v.add(csrInfo);
ASN1ObjectIdentifier oid = new ASN1ObjectIdentifier("0.0");
v.add(new DERSequence(oid));
v.add(new DERBitString(new byte[] {}));
byte[] encoded = new DERSequence(v).getEncoded();
byte[] PKCS10= DataSignGeneration(encoded);

After comments we can see that it is needed to create an unsigned PKCS10 request to send to javacard to be signed there, and get the result to build the signed PKCS10 request

Bouncycastle does not provide an API to perform the operation. I suggest to checkout the PKCS10 example and the source code of PKCS10CertificateRequestBuilder to adapt to use your Java card. If you want to use in android you need the special distribution spongycastle.

This is a working example to create an unsigned request (without java card, but it should be easy to adapt. Just the signature process)

public byte[] generateCSR (X500Name subject, PublicKey publicKey, String signatureAlgorithm) throws Exception{
    //Create the unsigned CSR
    CertificationRequestInfo info = new CertificationRequestInfo(
                    x500name, SubjectPublicKeyInfo.getInstance(publicKey.getEncoded()),new DERSet());

    //The CSR bytes to be signed
    byte dataToSign[] = info.getEncoded(ASN1Encoding.DER);

    //Send the CSR to the card
    byte signedData[] = signOnJavaCard (dataToSign,signatureAlgorithm);

    //Build the signed CSR
    AlgorithmIdentifier sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find(signatureAlgorithm);
    PKCS10CertificationRequest csr = new PKCS10CertificationRequest(
                    new CertificationRequest(info, sigAlgId, new DERBitString(signedData)));
    byte signedCSR = csr.getEncoded();

    //Verify signature validity
    ContentVerifierProvider verifier = new JcaContentVerifierProviderBuilder().setProvider(new BouncyCastleProvider()).build(publicKey);
    boolean valid = csr.isSignatureValid(verifier);

    return signedCSR;
}

To test the code I have used a local signature method

public byte signOnJavaCard (byte dataToSign[], String signatureAlgorithm)
    Signature signature = Signature.getInstance(signatureAlgorithm);
    signature.initSign(privateKey); //get the private key in some way...
    signature.update(dataToSign);
    return signature.sign();
}
pedrofb
  • 37,271
  • 5
  • 94
  • 142
  • When you want to send some data to a Javacard (the data to sign in this case), you need to put them inside an structure called APDU command. APDU command is consist of a fixed 5 byte header + an optional data body. The 5 index in the question is because of the fixed header. – Ebrahim Ghasemi Oct 24 '16 at 13:37
  • Because of hardware limitations in Javacard hardware, they don't support a lot of Java libraries and capabilities. For example they commonly doesn't support _int_ type. There is no bouncy castle library for javacards. – Ebrahim Ghasemi Oct 24 '16 at 13:40
  • 1
    Ok, @Abraham, understood the OFFSET_CDATA. Bouncycastle is used in Android code, only you have to send to the card the signature operation through the Bouncycastle api – pedrofb Oct 24 '16 at 13:45
  • Thank you so much. but I need unsigned pkcs#10 request becuse I shouls sign it with private key in java card. i use this code. isn't it correct?http://blog.pastelstudios.com/2015/04/21/create-unsigned-pkcs10-certification-request-bouncy-castle/ – Fatemeh Oct 24 '16 at 15:53
  • I do not know it is correct but it is incomplete. It does not explain which data has to be signed and how to build the signed CSR request. The best option is look at the bouncycastle source code. What version are you using? – pedrofb Oct 24 '16 at 16:10
  • I use spongycastle.in this code pkcs10 is UnsignedPkcs10CertificationRequest . should i signe it with private key for generate Pkcs10CertificationRequest? – Fatemeh Oct 24 '16 at 16:36
  • Excuse me ...I use scprov-jdk15on-1.47.0.2 – Fatemeh Oct 24 '16 at 16:38
  • I have included a full example using 1.49 (the latest code in bouncycastle github) to create an unsigned CSR, get the bytes to sign and build the final CSR. Probably it works also with 1.47 (check the source code if not). I do not know where the blog code came, but it is not present in the BC code – pedrofb Oct 24 '16 at 16:49
  • can you give me code address on github?I will sign csr . how to build the final CSR? – Fatemeh Oct 24 '16 at 17:00
  • I have included the link in the answer. Use `new PKCS10CertificationRequest(new CertificationRequest(info, sigAlgId, new DERBitString(signedData)));` You can see it in the answer – pedrofb Oct 24 '16 at 17:15
  • Excuse me...I get error on new DefaultSignatureAlgorithmIdentifierFinder().find( "SHA1withRSA") ans my program is stoped – Fatemeh Oct 24 '16 at 19:16
  • Its a library problem Ensure you have SC dependencies or try this alternative `sigAlgId = new AlgorithmIdentifier(new ASN1ObjectIdentifier("1.2.840.113549.1.1.5"))` for SHA1WithRsa – pedrofb Oct 24 '16 at 19:50
  • Thanks in advance. It works well and csr is generated. but i have to omit ContentVerifierProvider verifier = new JcaContentVerifierProviderBuilder().setProvider(new BouncyCastleProvider() ).build(currentpublickey); boolean valid = csr.isSignatureValid(verifier); I got error .can you tell me what is SC dendencies? – Fatemeh Oct 24 '16 at 20:36
  • excuse me..i understood. yes i added SC dendencies. i attached them in my quesion – Fatemeh Oct 24 '16 at 21:00
  • Excuse I cirrected it . and I executed boolean valid = csr.isSignatureValid(verifier); but valid value is false. I use Signature.ALG_RSA_SHA_PKCS1 for signatue. i'mnot sure .Is it rsa with sha1? – Fatemeh Oct 24 '16 at 21:33
  • It is the same algorithm sha1withrsa. If the verification fails, it means that the signed data do not match the message to be signed or public key. Probably you are not correctly sending or receiving the data to the card. Review your signature code and add a signature verification before returning the result – pedrofb Oct 25 '16 at 07:29
  • Excuseme dear pedrob. Can you hel me about this link http://stackoverflow.com/questions/40725518/error-malformed-content-in-signature-verification – Fatemeh Nov 21 '16 at 17:22
1

This error seems to mean that the private key (created when the certificate request was made) does not match the public key (the .crt file). The keypair is not successfully joined into a working SSL certificate.

Solution: Begin by importing the .crt file into the Personal certificate store for the local computer. (Start button > Run: MMC > File Menu > Add/Remove Snap-in > highlight Certificates snap-in and click the ADD button > select Computer Account and click Finish > Click OK > drill into Personal > Certificates > right-click and select All Tasks > select Import > guide to the .crt file.) At this point your certificate is basically a half-certificate. It is still missing its private key.

Second, double-click the crt certificate file you just imported, select the Details tab, scroll all the way down to Thumbprint and highlight Thumbprint. In the lower pane, block and copy all the letters of the thumbprint. Paste the thumbprint characters into notepad. Open the command prompt and run this command: Certutil /?

The command you’ll want to run is:

certutil -repairstore my “{insert all of the thumbprint characters here}”

When you see the response: “CertUtil: -repairstore command completed successfully” you should have a private key associated with the .crt file in the personal store. There should no longer be any need to run through the “Complete Certificate Request…” wizard. The certificate should show up in the IIS Manager’s list of server certificates at this point. It should also be available in the SSL Certificates drop-down list when attempting to edit the https binding for a website.

Refereence: https://blogs.msdn.microsoft.com/webtopics/2009/01/03/asn1-bad-tag-value-met-error-when-processing-a-certificate-request-in-iis-7/

  • Thank you for response. I generated key pair on java card ..why ssl?? I think bad csr is generated. but I wrote my code here. I don;t where do i make mistake in gereated key pair? – Fatemeh Oct 24 '16 at 07:01
  • All right, but try to associate both public and private keys so that keypair successfully joined together. Bad tag value error comes when there is not any association between generated keypair. – Malik Mumtaz Oct 24 '16 at 08:02
  • Thank you very much.but i want to generate in card and this work is flowed automatically. – Fatemeh Oct 24 '16 at 08:30