From jeremy at beopen.com Tue Sep 12 17:24:23 2000 From: jeremy at beopen.com (Jeremy Hylton) Date: Tue, 12 Sep 2000 11:24:23 -0400 (EDT) Subject: X.509 certs and Pisces In-Reply-To: <39BE345B.CB14E3A1@stroeder.com> References: <39BE345B.CB14E3A1@stroeder.com> Message-ID: <14782.19111.160898.185890@bitdiddle.concentric.net> >>>>> "MS" == Michael <=?iso-8859-1?Q?Str=F6der?= > writes: MS> HI! I'm trying to use Pisces (solely the asn1.py module for MS> now) to parse X.509v3 certificates (PKCS#7 blobs planned later). MS> Understanding your stuff is quite difficult for me because I'm a MS> complete ASN.1 newbie. And the X.509 ASN.1 is complex! The Pisces project actually started with an attempt to do X.509 certificates in Python. After spending a few weeks at it, I decided that SPKI was the way to go :-). MS> Well, I managed to write some classes for accessing X.509v3 MS> certs and X.509v2 CRLs but I'm still having some problems. I'd love to see them. MS> 1. Semantics of ASN1Object() attributes MS> I can't figure out what the difference is with the semantics of MS> accessing a parsed object directly, using .val or .data. At the MS> moment I'm just guessing. The only reason I use a data attribute is so that I can use UserList.UserList as a mixin class. The data and val attributes should be bound to the same object. In general, I did not expect that you would need to use the val attribute directly. Most (all?) of the instances of ASN1Object subclasses implement some methods for accessing the value or for comparison among objects. Can you offer an example where access .val is necessary? I'm not saying they are wrong, merely that I hadn't anticipated the need. MS> 2. Length of a RSA key MS> I'm trying to extract the RSA public-key in my e-mail cert which MS> is encoded like this: MS> RSAPublicKey ::= SEQUENCE { MS> modulus INTEGER, -- n MS> publicExponent INTEGER -- e -- } MS> I can extract it but module asn1 returns the modulus solely as MS> long integer. But I would be also interested in the length of MS> the RSA key. How to achieve that? I browsed through your code MS> it seems to me that a MS> class Integer(ASN1Object) MS> with method len() would help. If I understand correctly, there are places where you would rather have the raw bytes of n and e than the long integers they represent. Yes? And you want a len method so that you can find out how many bits, right? In other parts of Pisces, I have tended to use helper functions to convert between a long and a string: Crypto.Util.number defines str2long and long2str. You can convert the long to a string and then take the len of the string. I prefer this to have an Integer class, because there are many cases where it is handy for the parsed integer to be a number. MS> 3. Nested objects in X.509v3 extensions MS> The parsed objects of the X.509v3 extensions of my cert contains MS> some asn1.Contextual objects. I still can't figure out how to MS> handle them. I could probably explain better if you show me the fragment of the ASN.1 that defines the contextual encoding. The problem with contextual encodings is that the parser can not figure out what object is encoded without some information contained only in the type declaration. To deal with a contextual object, your application needs to provide the logic for determining what the type of the object should be. For example, let's say the type of attribute C depends on whether the value of attribute B is zero: if B is zero, C is an Integer; if not, C is a UTCTime. The application should test the value of B and the call the choose method, passing either asn1.INTEGER or asn1.UTCTIME as appropriate. Did that make sense? I don't actually use the Contextual class in the rest of Pisces, so I haven't had much opportunity to evaluate the design. It exists as a holdover from parsing the X.509 certificates. Jeremy From Peter.Sylvester at EdelWeb.fr Tue Sep 12 19:16:45 2000 From: Peter.Sylvester at EdelWeb.fr (Peter Sylvester) Date: Tue, 12 Sep 2000 19:16:45 +0200 (MET DST) Subject: Parsing X.509v3 extensions Message-ID: <200009121716.TAA17543@emeriau.edelweb.fr> Ich denk mir, ich kann ein wenig Deutsch schwaetzen: ASN1 hat so ein paar unangenehme Eigenheiten, die mit simplen ASN1-tools nicht ganz einfach zu bewaeltigen sind, insbesondere Konstrukte, bei denen die Syntax durch eine OID beschrieben sind, wie z.b. be algorithids usw. Man kann aber u.U eine Technik wie in Peter Gutmann's dumpasn1 anwenden: Alle Extensions haben sind OCTET STRINGS als Wert, und darin ist einfach wieder ASN1 kodiert. From jeremy at beopen.com Sat Sep 16 00:00:18 2000 From: jeremy at beopen.com (Jeremy Hylton) Date: Fri, 15 Sep 2000 18:00:18 -0400 (EDT) Subject: X.509 certs and Pisces In-Reply-To: <39C0FA0D.E7F2D4D9@stroeder.com> References: <39BE345B.CB14E3A1@stroeder.com> <14782.19111.160898.185890@bitdiddle.concentric.net> <39C0FA0D.E7F2D4D9@stroeder.com> Message-ID: <14786.39922.19383.69606@bitdiddle.concentric.net> >>>>> "MS" == Michael <=?iso-8859-1?Q?Str=F6der?= > writes: MS> I'm somewhat stuck parsing through X.509v3 some extensions. I MS> attached a pickled copy of a Contextual object as an MS> example. The type is defined in RFC2459 as MS> AuthorityKeyIdentifier. It looks like the pickle did not come through cleanly. I tried to load it and got an EOFError. MS> AuthorityKeyIdentifier ::= SEQUENCE { MS> keyIdentifier [0] KeyIdentifier OPTIONAL, MS> authorityCertIssuer [1] GeneralNames OPTIONAL, MS> authorityCertSerialNumber [2] CertificateSerialNumber MS> OPTIONAL MS> } MS> How can I extract the fields? MS> I thought I should use something like .choose(0) to get MS> keyIdentifier etc. But that did not work. I mean this special MS> case should be pretty simple or not? 0 does not correspond to any valid asn1 tag. You need to pass it the tag that corresponds to the type of data you want to get back. If you want an int, you do choose(asn1.INTEGER). The problem with a contextual type is that the encoded data is not self-contained. It is impossible to parse correctly without also using the asn1 type-decl to figure out what is actually being encoded. I can try again if you send me a valid pickle (and/or some encoded data) and enough ASN.1 to figure out what the types of those optional components actually are. Jeremy From jeremy at beopen.com Mon Sep 18 18:14:25 2000 From: jeremy at beopen.com (Jeremy Hylton) Date: Mon, 18 Sep 2000 12:14:25 -0400 (EDT) Subject: Parsing Contextual Objects again In-Reply-To: <39C621E5.80CE2D10@stroeder.com> References: <39BE345B.CB14E3A1@stroeder.com> <14782.19111.160898.185890@bitdiddle.concentric.net> <39C0FA0D.E7F2D4D9@stroeder.com> <14786.39922.19383.69606@bitdiddle.concentric.net> <39C621E5.80CE2D10@stroeder.com> Message-ID: <14790.16225.461748.946736@bitdiddle.concentric.net> Michael, This morning I took a closer look at the code and the example certificates you sent me. I definitely gave you bad advice in my last message. I think there are some problems with the parser for the explicit tagged elements, like the version number and the cert extensions. At the moment, though, there is a way to make it work. The Contextual object has two different methods that cause it to parse its contents. I told you about choose because I forgot about decode. >>> cert = asn1.parse(buf) >>> cert[0][0] >>> cert[0][0].decode() 2L >>> cert[0] SEQUENCE {[0] {2L}, 170063L, SEQUENCE {1.2.840.113549.1.1.4, None}, SEQUENCE {SET {[SEQUENCE {2.5.4.6, 'ZA'}]}, SET {[SEQUENCE {2.5.4.8, 'Western Cape'}]}, SET {[SEQUENCE {2.5.4.7, 'Durbanville'}]}, SET {[SEQUENCE {2.5.4.10, 'Thawte'}]}, SET {[SEQUENCE {2.5.4.11, 'Certificate Services'}]}, SET {[SEQUENCE {2.5.4.3, 'Personal Freemail RSA 1999.9.16'}]}}, SEQUENCE {UTCTime:'000518110812Z', UTCTime:'010518110812Z'}, SEQUENCE {SET {[SEQUENCE {2.5.4.4, 'Stroeder'}]}, SET {[SEQUENCE {2.5.4.42, 'Michael'}]}, SET {[SEQUENCE {2.5.4.3, 'Michael Stroeder'}]}, SET {[SEQUENCE {1.2.840.113549.1.9.1, 'michael at stroeder.com'}]}}, SEQUENCE {SEQUENCE {1.2.840.113549.1.1.1, None}, '0\201\211\002\201\201\000\253<_\371\232V\240B\316\017\273\027z\317\306\364\356\235H)\006x\322\377\033\231t\223\366\370\013\324\'g!!\331-/X\217\240\343q\265\270hn\352\310\010\345\215R~\261\264\363\021\210PG&{\034g\227\251+M\037\320\224z\376\267\322\037QqS\230C\300\236\342)|\364T\252\023\220\224\321A\3247\360)R\333\340\235\333\333\336;\272[\370\276\226\370\243\005L\013\345\243\014\316_\243\276\271Es\002\003\001\000\001'}, } >>> cert[0][7].decode() SEQUENCE {SEQUENCE {2.5.29.17, '0\026\201\024michael at stroeder.com'}, SEQUENCE {2.5.29.19, TRUE, '0\000'}, SEQUENCE {2.5.29.35, '0\026\200\024\210\253\361`\203fU\364\344X\307F\035\300a\275#\327\303\214'}} The decode method will do what you want. I'm going to look at the parser code again and see if it is possible to call decode automatically. If that is possible, it will simplify parsing a lot. Jeremy From jeremy at beopen.com Mon Sep 18 18:56:05 2000 From: jeremy at beopen.com (Jeremy Hylton) Date: Mon, 18 Sep 2000 12:56:05 -0400 (EDT) Subject: Parsing Contextual Objects again In-Reply-To: <39C64418.77952E49@stroeder.com> References: <39BE345B.CB14E3A1@stroeder.com> <14782.19111.160898.185890@bitdiddle.concentric.net> <39C0FA0D.E7F2D4D9@stroeder.com> <14786.39922.19383.69606@bitdiddle.concentric.net> <39C621E5.80CE2D10@stroeder.com> <14790.16225.461748.946736@bitdiddle.concentric.net> <39C64418.77952E49@stroeder.com> Message-ID: <14790.18725.291980.174492@bitdiddle.concentric.net> I think the pisces.asn1 module needs to be fixed to deal with explicitly tagged objects. I believe the choose method should only be required for implicit choices, i.e. an object where the different choices are not explicitly encoded. All of the X509 examples seem to be explicit, so the choose method should not be necessary. For the example you sent me earlier, I can use the decode method as follows: >>> an = asn1.parse('0\201\270\200\024\263wb\213h)Fqn\024\247!\363\372@\242\326*f\007\241\201\234\244\201\2310\201\2261\0130\011\006\003U\004\006\023\002DE1\0320\030\006\003U\004\010\024\021Baden-W\374rttemberg1\0220\020\006\003U\004\007\023\011Karlsruhe1\0240\022\006\003U\004\012\023\013at Michaels1\0130\011\006\003U\004\013\023\002CA1\0200\016\006\003U\004\003\023\007Root CA1"0 \006\011*\206H\206\367\015\001\011\001\026\023ca-admin at ms.inka.de\202\001\000') >>> an SEQUENCE {, , } >>> an[1].decode() >>> _.decode() SEQUENCE {SET {[SEQUENCE {2.5.4.6, 'DE'}]}, SET {[SEQUENCE {2.5.4.8, 'Baden-W\374rttemberg'}]}, SET {[SEQUENCE {2.5.4.7, 'Karlsruhe'}]}, SET {[SEQUENCE {2.5.4.10, 'at Michaels'}]}, SET {[SEQUENCE {2.5.4.11, 'CA'}]}, SET {[SEQUENCE {2.5.4.3, 'Root CA'}]}, SET {[SEQUENCE {1.2.840.113549.1.9.1, 'ca-admin at ms.inka.de'}]}} It looks like the first decode call gets the authorityCertIssuer that is tagged with [1]. The second decode call gets the directoryName that is tagged with [4]. The decode method modifies the contextual object in place, so a subsequent repr call produces: >>> an SEQUENCE {, [1] {[4] {SEQUENCE {SET {[SEQUENCE {2.5.4.6, 'DE'}]}, SET {[SEQUENCE {2.5.4.8, 'Baden-W\374rttemberg'}]}, SET {[SEQUENCE {2.5.4.7, 'Karlsruhe'}]}, SET {[SEQUENCE {2.5.4.10, 'at Michaels'}]}, SET {[SEQUENCE {2.5.4.11, 'CA'}]}, SET {[SEQUENCE {2.5.4.3, 'Root CA'}]}, SET {[SEQUENCE {1.2.840.113549.1.9.1, 'ca-admin at ms.inka.de'}]}}}}, } It looks like it is impossible to re-encode the Contextual object, which is another thing I need to fix in the asn1 module. Jeremy From jeremy at beopen.com Mon Sep 18 20:02:47 2000 From: jeremy at beopen.com (Jeremy Hylton) Date: Mon, 18 Sep 2000 14:02:47 -0400 (EDT) Subject: Parsing Contextual Objects again In-Reply-To: <39C653F9.D2F5AAA3@stroeder.com> References: <39BE345B.CB14E3A1@stroeder.com> <14782.19111.160898.185890@bitdiddle.concentric.net> <39C0FA0D.E7F2D4D9@stroeder.com> <14786.39922.19383.69606@bitdiddle.concentric.net> <39C621E5.80CE2D10@stroeder.com> <14790.16225.461748.946736@bitdiddle.concentric.net> <39C64418.77952E49@stroeder.com> <14790.18725.291980.174492@bitdiddle.concentric.net> <39C653F9.D2F5AAA3@stroeder.com> Message-ID: <14790.22727.989484.853680@bitdiddle.concentric.net> >>>>> "MS" == Michael Str?der > writes: >> The second decode call gets the directoryName that is tagged with >> [4]. MS> Yes. But this is the ASN.1 type GeneralName (which holds a MS> distinguished name in the above example). But I would expect a MS> sequence (type GeneralNames, not GeneralName)! I also expect a sequence, but that's not what is encoded! I am fairly confident that this part of the decoding is correct. I've confirmed it with Peter Gutmann's dumpasn1 program. (output attached) -------------- next part -------------- An embedded and charset-unspecified text was scrubbed... Name: out URL: -------------- next part -------------- The sequence that results from the decoding appears to be the RDNSequence for the Name [4]. >Name ::= CHOICE { -- only one possibility for now -- > rdnSequence RDNSequence } > >RDNSequence ::= SEQUENCE OF RelativeDistinguishedName > >DistinguishedName ::= RDNSequence > >RelativeDistinguishedName ::= > SET SIZE (1 .. MAX) OF AttributeTypeAndValue >> The decode method modifies the contextual object in place, MS> Aaaaaaaah! I will try using module copy now... Why? It modifies the object in place only so that after calling decode, the repr method is more helpful. I think it would be wasteful to copy it. Jeremy