error generating signed CSR with javacard (asn1 bad tag value)

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=
android
bouncycastle
javacard
csr
asked on Stack Overflow Oct 23, 2016 by Fatemeh • edited Oct 25, 2016 by pedrofb

3 Answers

4

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.

answered on Stack Overflow Oct 24, 2016 by Abraham • edited Oct 24, 2016 by Abraham
2

@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();
}
answered on Stack Overflow Oct 24, 2016 by pedrofb • edited Oct 24, 2016 by pedrofb
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/

answered on Stack Overflow Oct 24, 2016 by Malik Mumtaz

User contributions licensed under CC BY-SA 3.0