Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ASN.1: Handle 'ANY OPTIONAL' in grammar

An ANY object in an ASN.1 grammar that is marked OPTIONAL should be skipped
if there is no more data to be had.

This can be tested by editing X.509 certificates or PKCS#7 messages to
remove the NULL from subobjects that look like the following:

SEQUENCE {
OBJECT(2a864886f70d01010b);
NULL();
}

This is an algorithm identifier plus an optional parameter.

The modified DER can be passed to one of:

keyctl padd asymmetric "" @s </tmp/modified.x509
keyctl padd pkcs7_test foo @s </tmp/modified.pkcs7

It should work okay with the patch and produce EBADMSG without.

Signed-off-by: David Howells <dhowells@redhat.com>
Tested-by: Marcel Holtmann <marcel@holtmann.org>
Reviewed-by: David Woodhouse <David.Woodhouse@intel.com>

+21 -7
+11 -6
include/linux/asn1_ber_bytecode.h
··· 45 45 ASN1_OP_MATCH_JUMP = 0x04, 46 46 ASN1_OP_MATCH_JUMP_OR_SKIP = 0x05, 47 47 ASN1_OP_MATCH_ANY = 0x08, 48 + ASN1_OP_MATCH_ANY_OR_SKIP = 0x09, 48 49 ASN1_OP_MATCH_ANY_ACT = 0x0a, 50 + ASN1_OP_MATCH_ANY_ACT_OR_SKIP = 0x0b, 49 51 /* Everything before here matches unconditionally */ 50 52 51 53 ASN1_OP_COND_MATCH_OR_SKIP = 0x11, 52 54 ASN1_OP_COND_MATCH_ACT_OR_SKIP = 0x13, 53 55 ASN1_OP_COND_MATCH_JUMP_OR_SKIP = 0x15, 54 56 ASN1_OP_COND_MATCH_ANY = 0x18, 57 + ASN1_OP_COND_MATCH_ANY_OR_SKIP = 0x19, 55 58 ASN1_OP_COND_MATCH_ANY_ACT = 0x1a, 59 + ASN1_OP_COND_MATCH_ANY_ACT_OR_SKIP = 0x1b, 56 60 57 61 /* Everything before here will want a tag from the data */ 58 - #define ASN1_OP__MATCHES_TAG ASN1_OP_COND_MATCH_ANY_ACT 62 + #define ASN1_OP__MATCHES_TAG ASN1_OP_COND_MATCH_ANY_ACT_OR_SKIP 59 63 60 64 /* These are here to help fill up space */ 61 - ASN1_OP_COND_FAIL = 0x1b, 62 - ASN1_OP_COMPLETE = 0x1c, 63 - ASN1_OP_ACT = 0x1d, 64 - ASN1_OP_MAYBE_ACT = 0x1e, 65 - ASN1_OP_RETURN = 0x1f, 65 + ASN1_OP_COND_FAIL = 0x1c, 66 + ASN1_OP_COMPLETE = 0x1d, 67 + ASN1_OP_ACT = 0x1e, 68 + ASN1_OP_MAYBE_ACT = 0x1f, 66 69 67 70 /* The following eight have bit 0 -> SET, 1 -> OF, 2 -> ACT */ 68 71 ASN1_OP_END_SEQ = 0x20, ··· 79 76 #define ASN1_OP_END__SET 0x01 80 77 #define ASN1_OP_END__OF 0x02 81 78 #define ASN1_OP_END__ACT 0x04 79 + 80 + ASN1_OP_RETURN = 0x28, 82 81 83 82 ASN1_OP__NR 84 83 };
+8
lib/asn1_decoder.c
··· 24 24 [ASN1_OP_MATCH_JUMP] = 1 + 1 + 1, 25 25 [ASN1_OP_MATCH_JUMP_OR_SKIP] = 1 + 1 + 1, 26 26 [ASN1_OP_MATCH_ANY] = 1, 27 + [ASN1_OP_MATCH_ANY_OR_SKIP] = 1, 27 28 [ASN1_OP_MATCH_ANY_ACT] = 1 + 1, 29 + [ASN1_OP_MATCH_ANY_ACT_OR_SKIP] = 1 + 1, 28 30 [ASN1_OP_COND_MATCH_OR_SKIP] = 1 + 1, 29 31 [ASN1_OP_COND_MATCH_ACT_OR_SKIP] = 1 + 1 + 1, 30 32 [ASN1_OP_COND_MATCH_JUMP_OR_SKIP] = 1 + 1 + 1, 31 33 [ASN1_OP_COND_MATCH_ANY] = 1, 34 + [ASN1_OP_COND_MATCH_ANY_OR_SKIP] = 1, 32 35 [ASN1_OP_COND_MATCH_ANY_ACT] = 1 + 1, 36 + [ASN1_OP_COND_MATCH_ANY_ACT_OR_SKIP] = 1 + 1, 33 37 [ASN1_OP_COND_FAIL] = 1, 34 38 [ASN1_OP_COMPLETE] = 1, 35 39 [ASN1_OP_ACT] = 1 + 1, ··· 308 304 /* Decide how to handle the operation */ 309 305 switch (op) { 310 306 case ASN1_OP_MATCH_ANY_ACT: 307 + case ASN1_OP_MATCH_ANY_ACT_OR_SKIP: 311 308 case ASN1_OP_COND_MATCH_ANY_ACT: 309 + case ASN1_OP_COND_MATCH_ANY_ACT_OR_SKIP: 312 310 ret = actions[machine[pc + 1]](context, hdr, tag, data + dp, len); 313 311 if (ret < 0) 314 312 return ret; ··· 327 321 case ASN1_OP_MATCH: 328 322 case ASN1_OP_MATCH_OR_SKIP: 329 323 case ASN1_OP_MATCH_ANY: 324 + case ASN1_OP_MATCH_ANY_OR_SKIP: 330 325 case ASN1_OP_COND_MATCH_OR_SKIP: 331 326 case ASN1_OP_COND_MATCH_ANY: 327 + case ASN1_OP_COND_MATCH_ANY_OR_SKIP: 332 328 skip_data: 333 329 if (!(flags & FLAG_CONS)) { 334 330 if (flags & FLAG_INDEFINITE_LENGTH) {
+2 -1
scripts/asn1_compiler.c
··· 1401 1401 act = e->action ? "_ACT" : ""; 1402 1402 switch (e->compound) { 1403 1403 case ANY: 1404 - render_opcode(out, "ASN1_OP_%sMATCH_ANY%s,", cond, act); 1404 + render_opcode(out, "ASN1_OP_%sMATCH_ANY%s%s,", 1405 + cond, act, skippable ? "_OR_SKIP" : ""); 1405 1406 if (e->name) 1406 1407 render_more(out, "\t\t// %*.*s", 1407 1408 (int)e->name->size, (int)e->name->size,