MuntashirAkon/AppManager · error · KeyException
Unsupported ASN.1 tag {tag} encountered. Is this a valid RS
Error message
Unsupported ASN.1 tag {tag} encountered. Is this a valid RSA key? What it means
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.
Source
Thrown at app/src/main/java/io/github/muntashirakon/AppManager/crypto/ks/KeyStoreUtils.java:341
int length = b[pos++];
if ((length & 0x80) != 0) {
int extLen = 0;
for (int i = 0; i < (length & 0x7F); i++) {
extLen = (extLen << 8) | (b[pos++] & 0xFF);
}
length = extLen;
}
byte[] contents = new byte[length];
System.arraycopy(b, pos, contents, 0, length);
pos += length;
if (tag == 0x30) { // sequence
ASN1Parse(contents, integers);
} else if (tag == 0x02) { // Integer
BigInteger i = new BigInteger(contents);
integers.add(i);
} else {
throw new KeyException("Unsupported ASN.1 tag " + tag + " encountered. Is this a " + "valid RSA key?");
}
}
}
private static X509Certificate generateECDSACert(@NonNull PrivateKey privateKey, @NonNull PublicKey publicKey,
@NonNull String formattedSubject, long expiryDate)
throws OperatorCreationException, CertificateException {
Date notBefore = new Date();
Date notAfter = new Date(expiryDate);
org.bouncycastle.asn1.x500.X500Name x500Name = new org.bouncycastle.asn1.x500.X500Name(formattedSubject);
JcaContentSignerBuilder signerBuilder = new JcaContentSignerBuilder("SHA512withECDSA");
signerBuilder.setProvider(new BouncyCastleProvider());
SubjectPublicKeyInfo spki = SubjectPublicKeyInfo.getInstance(publicKey.getEncoded());
X509v3CertificateBuilder v3CertGen = new X509v3CertificateBuilder(x500Name,
BigInteger.valueOf(new SecureRandom().nextInt() & Integer.MAX_VALUE), notBefore, notAfter, x500Name, spki);
return new JcaX509CertificateConverter().getCertificate(v3CertGen.build(signerBuilder.build(privateKey)));
}
View on GitHub (pinned to 0152f468fc)
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
Example fix
// before
KeyStoreUtils.generatePrivateKey(misreadBytes); // KeyException: Unsupported ASN.1 tag 3
// after
byte[] der = Base64.decode(pem.replaceAll("-----(BEGIN|END) RSA PRIVATE KEY-----", "").trim(), Base64.DEFAULT);
if (isRsaKey(der)) { // check leading OID for rsaEncryption
KeyStoreUtils.generatePrivateKey(der);
} else {
throw new IllegalArgumentException("Only RSA private keys are supported here");
} Defensive patterns
Strategy: validation
Validate before calling
// Verify DER contains only SEQUENCE/INTEGER nodes before parsing
static boolean isPlainRsaDer(byte[] der) {
if (der == null || der.length == 0 || der[0] != 0x30) return false;
for (int i = 1; i < der.length; ) {
int tag = der[i++] & 0xFF;
if (tag != 0x30 && tag != 0x02) return false;
int len = der[i++] & 0xFF; // short-form lengths only for this check
i += len;
}
return true;
} Type guard
static boolean looksLikeRsaPrivateKey(byte[] der) {
return der != null && der.length > 2 && der[0] == 0x30; // top-level SEQUENCE
} Try / catch
try {
KeyStoreUtils.generatePrivateKey(der);
} catch (KeyException e) {
Log.e(TAG, "Not a parsable RSA key", e);
throw new IllegalArgumentException("Provide a PKCS#1 RSA DER key", e);
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- No KeyPair with alias ${RSA_KEY_ALIAS}
- No KeyPair with alias RSA_KEY_ALIAS
- Stream does not appear to be a properly formatted RSA key.
- Failed to setup metadata.
- Mode
AI-assisted analysis of MuntashirAkon/AppManager@0152f468fc (2026-09-12).
Data as JSON: /api/errors/3d46006301409449.
Report an issue: GitHub.