Search code examples
androidbouncycastlejavacardcsr

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


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=

Solution

  • @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();
    }