{"record":{"id":"3d46006301409449","repo":"MuntashirAkon/AppManager","slug":"unsupported-asn-1-tag-tag-encountered-is-this-a-valid-rsa","errorCode":null,"errorMessage":"Unsupported ASN.1 tag {tag} encountered.  Is this a valid RSA key?","messagePattern":"Unsupported ASN\\.1 tag (.+?) encountered\\.  Is this a valid RSA key\\?","errorType":"exception","errorClass":"KeyException","httpStatus":null,"severity":"error","filePath":"app/src/main/java/io/github/muntashirakon/AppManager/crypto/ks/KeyStoreUtils.java","lineNumber":341,"sourceCode":"            int length = b[pos++];\n            if ((length & 0x80) != 0) {\n                int extLen = 0;\n                for (int i = 0; i < (length & 0x7F); i++) {\n                    extLen = (extLen << 8) | (b[pos++] & 0xFF);\n                }\n                length = extLen;\n            }\n            byte[] contents = new byte[length];\n            System.arraycopy(b, pos, contents, 0, length);\n            pos += length;\n\n            if (tag == 0x30) {  // sequence\n                ASN1Parse(contents, integers);\n            } else if (tag == 0x02) {  // Integer\n                BigInteger i = new BigInteger(contents);\n                integers.add(i);\n            } else {\n                throw new KeyException(\"Unsupported ASN.1 tag \" + tag + \" encountered.  Is this a \" + \"valid RSA key?\");\n            }\n        }\n    }\n\n    private static X509Certificate generateECDSACert(@NonNull PrivateKey privateKey, @NonNull PublicKey publicKey,\n                                                     @NonNull String formattedSubject, long expiryDate)\n            throws OperatorCreationException, CertificateException {\n        Date notBefore = new Date();\n        Date notAfter = new Date(expiryDate);\n        org.bouncycastle.asn1.x500.X500Name x500Name = new org.bouncycastle.asn1.x500.X500Name(formattedSubject);\n        JcaContentSignerBuilder signerBuilder = new JcaContentSignerBuilder(\"SHA512withECDSA\");\n        signerBuilder.setProvider(new BouncyCastleProvider());\n        SubjectPublicKeyInfo spki = SubjectPublicKeyInfo.getInstance(publicKey.getEncoded());\n        X509v3CertificateBuilder v3CertGen = new X509v3CertificateBuilder(x500Name,\n                BigInteger.valueOf(new SecureRandom().nextInt() & Integer.MAX_VALUE), notBefore, notAfter, x500Name, spki);\n        return new JcaX509CertificateConverter().getCertificate(v3CertGen.build(signerBuilder.build(privateKey)));\n    }\n","sourceCodeStart":323,"sourceCodeEnd":359,"githubUrl":"https://github.com/MuntashirAkon/AppManager/blob/0152f468fc9463ee02dc2ca83f6fe4989a2c4ca5/app/src/main/java/io/github/muntashirakon/AppManager/crypto/ks/KeyStoreUtils.java#L323-L359","documentation":"ASN1Parse is a hand-rolled minimal DER/BER walker that only understands two ASN.1 tags: SEQUENCE (0x30) and INTEGER (0x02), which is all a plain RSA key structure should contain. If it meets any other tag — e.g. a BIT STRING, OCTET STRING, or an encoded key with algorithm parameters — it cannot map it to an RSA integer list and throws KeyException. This guards against passing a non-RSA or improperly encoded key to RSA key generation/parsing.","triggerScenarios":"Calling generatePrivateKey (or ASN1Parse directly) with a key blob whose DER payload contains a tag other than 0x30 or 0x02 — e.g. an EC key, a PKCS#8/PKCS#1 wrapper with extra fields, a truncated/corrupted file where the parser misreads a length and lands mid-field, or a key with OID/parameter blocks.","commonSituations":"Developer passes an EC or Ed25519 key where an RSA key is required; key file was Base64-decoded incorrectly (headers not stripped); key file corrupted in transfer; legacy DER produced by a non-standard tool.","solutions":["Verify the key file is actually an RSA key (e.g. `openssl rsa -in key.pem -check`) and convert EC/other types if RSA was intended","Strip PEM armor and decode Base64 correctly before passing raw DER to the parser","Re-export the key from its source in PKCS#1 DER form so the payload only contains SEQUENCE and INTEGER nodes","Inspect the DER structure (e.g. `openssl asn1parse -inform DER -in key.der`) to find the unexpected tag and fix the input","If the source truly cannot be an RSA key, use a key parser that handles the actual key type instead of KeyStoreUtils' RSA-only walker"],"exampleFix":"// before\nKeyStoreUtils.generatePrivateKey(misreadBytes); // KeyException: Unsupported ASN.1 tag 3\n// after\nbyte[] der = Base64.decode(pem.replaceAll(\"-----(BEGIN|END) RSA PRIVATE KEY-----\", \"\").trim(), Base64.DEFAULT);\nif (isRsaKey(der)) { // check leading OID for rsaEncryption\n    KeyStoreUtils.generatePrivateKey(der);\n} else {\n    throw new IllegalArgumentException(\"Only RSA private keys are supported here\");\n}","handlingStrategy":"validation","validationCode":"// Verify DER contains only SEQUENCE/INTEGER nodes before parsing\nstatic boolean isPlainRsaDer(byte[] der) {\n    if (der == null || der.length == 0 || der[0] != 0x30) return false;\n    for (int i = 1; i < der.length; ) {\n        int tag = der[i++] & 0xFF;\n        if (tag != 0x30 && tag != 0x02) return false;\n        int len = der[i++] & 0xFF; // short-form lengths only for this check\n        i += len;\n    }\n    return true;\n}","typeGuard":"static boolean looksLikeRsaPrivateKey(byte[] der) {\n    return der != null && der.length > 2 && der[0] == 0x30; // top-level SEQUENCE\n}","tryCatchPattern":"try {\n    KeyStoreUtils.generatePrivateKey(der);\n} catch (KeyException e) {\n    Log.e(TAG, \"Not a parsable RSA key\", e);\n    throw new IllegalArgumentException(\"Provide a PKCS#1 RSA DER key\", e);\n}","preventionTips":["Validate the key type with openssl before import","Always strip PEM headers and Base64-decode correctly","Inspect DER structure when a key fails to parse"],"tags":["asn1","rsa","crypto","key-parsing"],"backgroundTag":"invalid-argument-format","analyzedSha":"0152f468fc9463ee02dc2ca83f6fe4989a2c4ca5","analyzedAt":"2026-09-12T14:03:37.243Z","contentChangedAt":"2026-09-12T14:03:37.243Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}