PyDERASN: si shkrova një bibliotekë ASN.1 me slots dhe blobs

ASN.1 Kjo është një standard (ISO, ITU-T, GOST) i gjuhës që përshkruan informacionin e strukturuar, si dhe rregullat e kodifikimit të këtij informacioni. Për mua si programues, është thjesht një format tjetër serializimi dhe reprezentimi të të dhënave, në përputhje me JSON, XML, XDR dhe të tjera. Ai është shumë i përhapur në jetën tonë të përditshme, dhe shumë të tjerë hasin në të: në komunikimin celular, telefonik, VoIP (UMTS, LTE, WiMAX, SS7, H.323), në protokollet rrjetërore (LDAP, SNMP, Kerberos), në çdo gjë që ka të bëjë me kriptografinë (X.509, CMS, standardet PKCS), në kartat bankare dhe pasaportat biometrike, dhe në shumë vende të tjera.

Ky artikull shqyrton PyDERASN: një bibliotekë Python ASN.1 që përdoret aktivisht në projekte që lidhen me kriptografinë në Atlasin.

PyDERASN: si shkrova një bibliotekë ASN.1 me slots dhe blobs
Në të vërtetë, nuk është e rekomandueshme të përdoret ASN.1 për detyra kriptografike: ASN.1 dhe kodekët e tij janë të komplikuar. Kjo do të thotë se kodi nuk do të jetë i thjeshtë, dhe kjo gjithmonë përbën një vektor tjetër sulmi. Mjafton të shikoni listën e dobësive në bibliotekat ASN.1. Bruce Schneier në librin e tij Inxhinieria e kriptografisë po ashtu nuk e rekomandon këtë standard për shkak të kompleksitetit të tij: "Kodifikimi më i njohur TLV është ASN.1, por është jashtëzakonisht i komplikuar dhe ne largohemi nga të." Por, fatkeqësisht, sot kemi infrastrukturës së çelësave publikë të cilat përdorin aktive certifikatat X.509, CRL, OCSP, TSP, protokollet CMP, CMC, mesazhe CMS, dhe një sërë standardesh PKCS. Prandaj, është e nevojshme të dish të punosh me ASN.1, nëse merresh me diçka që ka të bëjë me kriptografinë.

ASN.1 mund të kodifikohet në shumë mënyra / kodekësh:

  • BER (Rregullat e Kodifikimit Bazik)
  • CER (Rregullat e Kodifikimit Kanonik)
  • DER (Rregullat e Kodifikimit tĂ« Distinguar)
  • GSER (Rregullat e Kodifikimit tĂ« String-ut e PĂ«rgjithshĂ«m)
  • JER (Rregullat e Kodifikimit JSON)
  • LWER (Rregullat e Kodifikimit tĂ« LehtĂ«)
  • OER (Rregullat e Kodifikimit tĂ« Octet)
  • PER (Rregullat e Kodifikimit tĂ« Paketave)
  • SER (Rregullat specifike pĂ«r Kodifikimin e Signaleve)
  • XER (Rregullat e Kodifikimit XML)

dhe shumĂ« tĂ« tjera. Por pĂ«r detyrat kriptografike, nĂ« praktikĂ« pĂ«rdoren vetĂ«m dy: BER dhe DER. Edhe nĂ« dokumentet XML tĂ« nĂ«nshkruara (XMLDSig, XAdES) ende do tĂ« ketĂ« objekte ASN.1 DER tĂ« koduara nĂ« Base64, ashtu si nĂ« protokollin e orientuar me JSON ACME nga Let’s Encrypt. ËshtĂ« mĂ« mirĂ« tĂ« kuptoni tĂ« gjitha kĂ«to kodekĂ«t dhe parimet e kodifikimit BER / CER / DER qĂ« mund tĂ« gjenden nĂ« artikuj dhe libra: ASN.1 me fjalĂ« tĂ« thjeshta, ASN.1 - Komunikimi mes sistemeve heterogjene nga Olivier Dubuisson, ASN.1 i PlotĂ« nga Prof. John Larmouth.

BER Ă«shtĂ« njĂ« format TLV binar i orientuar ndaj byte (p.sh. PER, qĂ« Ă«shtĂ« popullor nĂ« komunikimin celular — e orientuar ndaj bit). Çdo element kodifikohet si: taga (Tag), qĂ« identifikon llojin e elementit tĂ« koduar (numĂ«r i plotĂ«, string, datĂ«, etj.), gjatĂ«si (Length) e pĂ«rmbajtjes dhe vetĂ« pĂ«rmbajtjes.Value). BER opcionalisht lejon mos t'i jepet njĂ« vlerĂ« tĂ« gjatĂ«, duke vendosur njĂ« vlerĂ« tĂ« veçantĂ« pĂ«r gjatĂ«si tĂ« pacaktuar dhe duke e pĂ«rfunduar mesazhin me etiketĂ«n End-Of-Octets. PĂ«rveç kodimit tĂ« gjatĂ«, nĂ« BER ka shumĂ« variabilitet nĂ« mĂ«nyrĂ«n e kodimit tĂ« tipeve tĂ« tĂ« dhĂ«nave, siç janĂ«:

  • INTEGER, OBJECT IDENTIFIER, BIT STRING dhe gjatĂ«si elementi mund tĂ« jenĂ« tĂ« panormalizuar (nuk janĂ« koduar nĂ« formĂ«n minimale);
  • BOOLEAN Ă«shtĂ« i vĂ«rtetĂ« pĂ«r çdo pĂ«rmbajtje jo zero;
  • BIT STRING mund tĂ« pĂ«rmbajĂ« ‘bita’ tĂ« panevojshĂ«m zero;
  • BIT STRING, OCTET STRING dhe tĂ« gjithĂ« tipet e tjera tĂ« vargjeve tĂ« nxjerra, pĂ«rfshirĂ« datĂ«n/koha, mund tĂ« copĂ«zohen nĂ« fragmente (chunk) me gjatĂ«si tĂ« ndryshme, gjatĂ«sia e tĂ« cilave gjatĂ« (de)kodimit nuk dihet mĂ« parĂ«;
  • UTCTime/GeneralizedTime mund tĂ« kenĂ« mĂ«nyra tĂ« ndryshme pĂ«r tĂ« caktuar zhvendosjen e zonĂ«s kohore dhe ‘bita’ tĂ« panevojshĂ«m zero tĂ« sekondave;
  • Vlerat DEFAULT tĂ« SEQUENCE mund tĂ« kodohen, ose jo;
  • Emrat e vlerave tĂ« fundit tĂ« biterve nĂ« BIT STRING mund tĂ« kodohen sipas dĂ«shirs;
  • SEQUENCE (OF)/SET (OF) mund tĂ« kenĂ« rend tĂ« çfarĂ«do tĂ« elementeve.

Për shkak të të gjitha të mësipërmeve, kodimi i të dhënave në një mënyrë që ato të jenë identike me formën origjinale nuk është gjithmonë i mundur. Prandaj, u shpik një nënpjesë rregullash: DER - një rregull që rregullon vetëm një mënyrë të pranueshme të kodimit, e cila është kritike për detyrat kriptografike, ku, për shembull, ndryshimi i një biter do ta bënte nënshkrimin ose shumën kontrolluese të pavlefshme. DER ka një disavantazh të konsiderueshëm: gjatësi të të gjithë elementeve duhet të jenë të njohura paraprakisht gjatë kodimit, gjë që nuk lejon serializimin e të dhënave në mënyrë të vazhdueshme. Codec CER është i lirë nga ky disavantazh, duke garantuar një paraqitje unike të të dhënave. Fatkeqësisht (ose e lumtur që nuk kemi akoma dekoderë më të ndërlikuar?), ai nuk u bë popullor. Prandaj, në praktikë ne hasim përdorim 'të përzier' të të dhënave të koduara në BER dhe DER. Duke qenë se CER dhe DER janë nënpjesë të BER, çdo dekoder BER është në gjendje t'i trajtojë ato.

Problemet me pyasn1

Në punë ne shkruajmë shumë programe në Python që lidhen me kriptografinë. Dhe disa vjet më parë, zgjedhja e librarive të lira ishte pothuajse e pamundur: ose ishin libra shumë të nivelit të ulët, që lejonin vetëm kodimin/dekodimin, për shembull, të një numri të plotë dhe një titull strukture, ose ishte libri pyasn1. Ne kemi jetuar atje për disa vite dhe fillimisht ishim shumë të kënaqur, pasi ajo lejonte punën me strukturat ASN.1 si objekte me nivele të larta: për shembull, objekti i dekoduar i certifikatës X.509 na lejon të qasemi në fushat e tij përmes një interface thesar: cert[«tbsCertificate»][«serialNumber»] do të tregojë numrin serial të kësaj certifikate. Po ashtu, mund të "ndërtojmë" objekte komplekse duke punuar me to si lista, thesare, pastaj thjesht thërrisni funksionin pyasn1.codec.der.encoder.encode dhe të merrni një paraqitje të serializuar të dokumentit.

MegjithatĂ«, dolĂ«n nĂ« pah disavantazhe, probleme dhe kufizime. NĂ« pyasn1 kishte dhe, fatkeqĂ«sisht, ende ka gabime: nĂ« momentin e shkruajtur tĂ« kĂ«tij artikulli, nĂ« pyasn1 njĂ« nga tipi bazik — GeneralizedTime, decodifikohet dhe kodifikohet padrejtĂ«. ndryshe.

Në projektet tona, për të kursyer hapësirë, shpesh ruajmë vetëm rrugën e skedarit, offsetin dhe gjatësinë në bajta të objektit që duam të referojmë. Për shembull, një skedar i nënshkruar arbitrar do të gjendet me siguri në strukturën ASN.1 të CMS SignedData:

  0     [1,3,1018]  ContentInfo SEQUENCE
  4     [1,1,   9]   . contentType: ContentType OBJECT IDENTIFIER 1.2.840.113549.1.7.2 (id_signedData)
 19-4   [0,0,1003]   . content: [0] EXPLICIT [UNIV 16] ANY
 19     [1,3, 999]   . . DEFINED BY id_signedData: SignedData SEQUENCE
 23     [1,1,   1]   . . . version: CMSVersion INTEGER v3 (03)
 26     [1,1,  19]   . . . digestAlgorithms: DigestAlgorithmIdentifiers SET OF
                           [...]
 47     [1,3, 769]   . . . encapContentInfo: EncapsulatedContentInfo SEQUENCE
 51     [1,1,   8]   . . . . eContentType: ContentType OBJECT IDENTIFIER 1.3.6.1.5.5.7.12.2 (id_cct_PKIData)
 65-4   [1,3, 751]   . . . . eContent: [0] EXPLICIT OCTET STRING 751 bytes OPTIONAL

                 KËTU NDODH I PËRGJIGJSHËM I FALAS PËR SKEDARIN E NËNSHKUAR ME SHKËLQIM 751 bajt

820     [1,2, 199]   . . . signerInfos: SignerInfos SET OF
823     [1,2, 196]   . . . . 0: SignerInfo SEQUENCE
826     [1,1,   1]   . . . . . version: CMSVersion INTEGER v3 (03)
829     [0,0,  22]   . . . . . sid: SignerIdentifier CHOICE subjectKeyIdentifier
                               [...]
956     [1,1,  64]   . . . . . signature: SignatureValue OCTET STRING 64 bytes
                     . . . . . . C1:B3:88:BA:F8:92:1C:E6:3E:41:9B:E0:D3:E9:AF:D8
                     . . . . . . 47:4A:8A:9D:94:5D:56:6B:F0:C1:20:38:D2:72:22:12
                     . . . . . . 9F:76:46:F6:51:5F:9A:8D:BF:D7:A6:9B:FD:C5:DA:D2
                     . . . . . . F3:6B:00:14:A4:9D:D7:B5:E1:A6:86:44:86:A7:E8:C9

dhe ne mund tĂ« marrim skedarin origjinal tĂ« nĂ«nshkruar nĂ« offsetin 65 byte, me gjatĂ«si 751 byte. pyasn1 nuk ruan kĂ«tĂ« informacion nĂ« objektet e tij tĂ« dekoduara. U shkrua njĂ« bibliotekĂ« e njohur si TLVSeeker — njĂ« bibliotekĂ« e vogĂ«l qĂ« lejon dekodimin e etiketave dhe gjatĂ«si tĂ« objekteve, nĂ« ndĂ«rfaqen e sĂ« cilĂ«s urdhĂ«ruam 'shko te etiqueta tjetĂ«r', 'hyni brenda etiketĂ«s' (nĂ« brendĂ«si tĂ« objektit SEQUENCE), 'shko te etiketĂ« tjetĂ«r', 'raporto offset-in dhe gjatĂ«si e objektit ku ndodhemi'. Kjo ishte njĂ« eksplorim 'manual' i tĂ« dhĂ«nave ASN.1 DER-serializuar. Por nuk mund tĂ« punonte kĂ«shtu me tĂ« dhĂ«nat BER-serializuar, sepse, pĂ«r shembull, njĂ« varg byte OCTET STRING mund tĂ« ishte koduar nĂ« formĂ«n e disa copĂ«za.

NjĂ« disavantazh tjetĂ«r pĂ«r ne nĂ« pyasn1 Ă«shtĂ« pamundĂ«sia pĂ«r tĂ« kuptuar nga objektet e dekoduara, nĂ«se njĂ« fushĂ« e caktuar ishte e pranishme nĂ« SEQUENCE apo jo. PĂ«r shembull, nĂ«se struktura pĂ«rmban fushĂ«n Field SEQUENCE OF Smth OPTIONAL, ajo mund tĂ« jetĂ« plotĂ«sisht e munguar nĂ« tĂ« dhĂ«nat qĂ« erdhĂ«n (OPTIONAL), por gjithashtu mund tĂ« jetĂ« e pranishme, por me gjatĂ«si zero (listĂ« e zbrazĂ«t). NĂ« pĂ«rgjithĂ«si, kjo nuk mund tĂ« zbulohej. Dhe kjo nevojitet pĂ«r njĂ« verifikim rigoroz tĂ« vlefshmĂ«risĂ« sĂ« tĂ« dhĂ«nave qĂ« erdhĂ«n. Imagjinoni qĂ« ndonjĂ« autoritet i besueshmĂ«risĂ« do tĂ« kishte lĂ«shuar njĂ« certifikatĂ« me tĂ« dhĂ«na qĂ« nuk ishin 'plotĂ«sisht' valide nga pikĂ«pamja e skemave ASN.1! PĂ«r shembull, autoriteti i besueshmĂ«risĂ« 'TÜRKTRUST Elektronik Sertifika Hizmet Sağlayıcısı' nĂ« certifikatĂ«n e tij rrĂ«njĂ«sore kaloi pĂ«rtej kufijve tĂ« pranueshĂ«m. RFC 5280 kuptimi i kufijve tĂ« gjatĂ« tĂ« komponentit subject — nuk mund tĂ« dekodohej ndershĂ«m sipas skemĂ«s. Kodi DER kĂ«rkon qĂ« fusha, e cila ka vlerĂ«n DEFAULT, tĂ« mos kodifikohet gjatĂ« transferimit — nĂ« jetĂ«, dokumente tĂ« tilla hasen dhe versioni i parĂ« i PyDERASN madje e lejonte me vetĂ«dije njĂ« sjellje tĂ« tillĂ« jo valide (nga pikĂ«pamja DER) pĂ«r shkak tĂ« pĂ«rputhshmĂ«risĂ« sĂ« prapme.

Një tjetër kufizim është pamundësia për të kuptuar lehtësisht në cilin format (BER/DER) është koduar ndonjë objekt në strukturë. Për shembull, standardi CMS thotë që mesazhi kodifikohet në BER, por fusha signedAttrs, mbi të cilën formohet nënshkrimi kriptografik, duhet të jetë në DER. Nëse e dekodojmë me DER, do të përballemi me probleme gjatë përpunimit të CMS-së, nëse e dekodojmë me BER, nuk do të kuptojmë në cilin format ishte signedAttrs. Si rezultat, do të na duhet të kërkojmë pozitat e çdo fushe signedAttrs me TLVSeeker (analogu i të cilit nuk ekziston në pyasn1) dhe ta dekodojmë veçmas, duke e nxjerrë nga prezantimi i serializuar, me DER.

Një mundësi e dëshiruar për ne ishte përpunimi automatik i fushave DEFINED BY, të cilat shfaqen shumë shpesh. Pas dekodimit të strukturës ASN.1, mund të na mbeten shumë fusha ANY, të cilat duhet të përpunohen më tej sipas skemës, e cila zgjidhet në bazë të OBJECT IDENTIFIER të caktuar në fushën e strukturës. Në kodin Python, kjo do të thotë të shkruajmë if dhe të mëtejshëm thirrjen e dekoduesit për fushën ANY.

Shfaqja e PyDERASN

Në Atlas, ne rregullisht, kur gjejmë ndonjë problem ose përmirësojmë programet e lira që përdorim, dërgojmë patch-e lart. Në pyasn1, ne kemi dërguar disa herë përmirësime, por kodi i pyasn1 nuk është nga ata më të thjeshtë për t'u kuptuar dhe ndonjëherë ka pasur ndryshime të papërputhshme API që na godisnin. Gjithashtu, ne jemi mësuar të shkruajmë teste me testimin generativ, gjë që nuk e kishim në pyasn1.

NĂ« njĂ« ditĂ« tĂ« bukur, vendosa se ishte e mjaftueshme dhe ishte koha tĂ« pĂ«rpiqesha pĂ«r tĂ« shkruar njĂ« bibliotekĂ« tĂ« vetĂ«n me __slot__-a, offset-e dhe blob-e tĂ« dukshme! Thjesht krijimi i njĂ« kodeku ASN.1 do tĂ« ishte i pamjaftueshĂ«m — duhej tĂ« pĂ«rkthente tĂ« gjithĂ« projektet tona tĂ« varura nga njĂ«ri-tjetri nĂ« tĂ«, dhe kjo pĂ«rbĂ«nte qindra mijĂ«ra rreshta kodi nĂ« tĂ« cilĂ«t ka shumĂ« punĂ« me strukturat ASN.1. Pra, njĂ« nga kĂ«rkesat pĂ«r tĂ« ishte lehtĂ«sia e pĂ«rkthimit tĂ« kodit aktual tĂ« pyasn1. Duke kaluar gjithĂ« pushimin tim, shkrova kĂ«tĂ« bibliotekĂ«, pĂ«rktheva tĂ« gjitha projektet nĂ« tĂ«. Duke marrĂ« parasysh se kishin pothuajse 100%-kcoverage me teste, kjo do tĂ« thoshte dhe funksionalitetin e plotĂ« tĂ« bibliotekĂ«s.

PyDERASN, njësoj, ka praktikisht 100%-otik-kcoverage me teste. Përdoret testimi generativ me bibliotekën e mrekullueshme hypothesis. gjithashtu u krye dhe fuzzing py-afl-em në makinat me 32 bërthama. Megjithëse ne kemi mbetur praktikisht pa kod Python2, PyDERASN ende siguron përputhshmëri me të dhe për këtë arsye ka vetëm një six varësi. Përveç kësaj, ai është testuar ndaj ASN.1:2008 compliance test suite.

Parimi i punĂ«s me tĂ« Ă«shtĂ« i ngjashĂ«m me pyasn1 — puna me objekte Python tĂ« nivelit tĂ« lartĂ«. PĂ«rshkrimi i skemave ASN.1 Ă«shtĂ« i ngjashĂ«m.

class TBSCertificate(Sequence):
    schema = (
        ("version", Version(expl=tag_ctxc(0), default="v1")),
        ("serialNumber", CertificateSerialNumber()),
        ("signature", AlgorithmIdentifier()),
        ("issuer", Name()),
        ("validity", Validity()),
        ("subject", Name()),
        ("subjectPublicKeyInfo", SubjectPublicKeyInfo()),
        ("issuerUniqueID", UniqueIdentifier(impl=tag_ctxp(1), optional=True)),
        ("subjectUniqueID", UniqueIdentifier(impl=tag_ctxp(2), optional=True)),
        ("extensions", Extensions(expl=tag_ctxc(3), optional=True)),
    )

MegjithatĂ«, PyDERASN ka njĂ« ngjashmĂ«ri me tipizimin e fortĂ«. NĂ« pyasn1, nĂ«se njĂ« fushĂ« kishte tip CMSVersion(INTEGER), mund t’i atribuoheshin int ose INTEGER. PyDERASN kĂ«rkon fort qĂ« objekti i atribuar tĂ« jetĂ« pikĂ«risht CMSVersion. PĂ«rveç faktit qĂ« ne shkruajmĂ« kodin nĂ« Python3, ne gjithashtu pĂ«rdorim annotatat e tipit, prandaj nĂ« funksionet tona do tĂ« kemi jo argumente tĂ« paqartĂ« si def func(serial, contents), por def func(serial: CertificateSerialNumber, contents: EncapsulatedContentInfo), dhe PyDERASN ndihmon nĂ« ruajtjen e njĂ« kodi tĂ« tillĂ«.

NĂ« tĂ« njĂ«jtĂ«n kohĂ«, nĂ« PyDERASN ka shumĂ« lehtĂ«sira tĂ« tilla tĂ« tipizimit. pyasn1 nuk lejonte nĂ« SubjectKeyIdentifier().subtype(implicitTag=Tag(
)) qĂ« njĂ« fushĂ« t’i atribuohej objektit SubjectKeyIdentifier() (pa TAG-un IMPLICIT tĂ« nevojshĂ«m) dhe shpesh vinte pĂ«r tĂ« kopjuar dhe rikrijuar objekte vetĂ«m pĂ«r shkak tĂ« etiketave IMPLICIT/EXPLICIT tĂ« ndryshuara. PyDERASN rreptĂ«sisht ndjek vetĂ«m tipin bazĂ« — etiketat ai do t’i vendosĂ« automatikisht nga struktura e skemĂ«s ASN.1 ekzistuese. Kjo e thjeshton ndjeshĂ«m kodin e aplikacioneve.

NĂ«se ndodh njĂ« gabim gjatĂ« dekodimit, atĂ«herĂ« nĂ« pyasn1 nuk Ă«shtĂ« e lehtĂ« tĂ« kuptohet se ku pikĂ«risht ka ndodhur. PĂ«r shembull, nĂ« certifikatĂ«n turke tĂ« pĂ«rmendur mĂ« lart do tĂ« marrim kĂ«tĂ« gabim: UTF8String (tbsCertificate:issuer:rdnSequence:3:0:value:DEFINED BY 2.5.4.10:utf8String) (nĂ« 138) kufizime tĂ« paplotĂ«suara: 1 ⇐ 77 ⇐ 64 Kur shkruhen struktura ASN.1, njerĂ«zit mund tĂ« gabojnĂ« dhe kjo ndihmon nĂ« lehtĂ«simin e zbulsimit tĂ« aplikacioneve ose identifikimin e problemeve me dokumentet e koduara tĂ« palĂ«s tjetĂ«r.

Në versionin e parë PyDERASN nuk kishte mbështetje për kodimin BER. Ajo u shfaq shumë më vonë dhe ende nuk mbështetet përpunimi UTCTime/GeneralizedTime me zona të kohës. Kjo do të vijë në të ardhmen, pasi projekti po shkruhet kryesisht në kohën e lirë nga puna.

Gjithashtu, nĂ« versionin e parĂ« nuk ka pasur funksionalitet pĂ«r fushat DEFINED BY. Pas disa muajsh, kjo mundĂ«si u bĂ« e mundshme dhe filloi tĂ« pĂ«rdoret aktivisht, duke e reduktuar ndjeshĂ«m kodin e aplikacioneve — nĂ« njĂ« operacion dekodimi mund tĂ« merrni aty pĂ«r aty tĂ«rĂ« strukturĂ«n e zbĂ«rthyer nĂ« thellĂ«si. PĂ«r kĂ«tĂ«, nĂ« skemĂ« caktohen cilat fusha «determinojnë» çfarĂ«. PĂ«r shembull, pĂ«rshkrimi i skemĂ«s CMS:

class ContentInfo(Sequence):
    schema = (
        ("contentType", ContentType(defines=((("content",), {
            id_authenticatedData: AuthenticatedData(),
            id_digestedData: DigestedData(),
            id_encryptedData: EncryptedData(),
            id_envelopedData: EnvelopedData(),
            id_signedData: SignedData(),
        }),))),
        ("content", Any(expl=tag_ctxc(0))),
    )

tregon se nĂ«se contentType do tĂ« pĂ«rmbajĂ« OID me vlerĂ« id_signedData, atĂ«herĂ« fusha content (e cila ndodhet nĂ« kĂ«tĂ« SEQUENCE) duhet tĂ« dekodohet sipas skemĂ«s SignedData. Pse ka kaq shumĂ« kllapa? NjĂ« fushĂ« mund tĂ« «determinojë» disa fusha njĂ«kohĂ«sisht, siç ndodh nĂ« strukturat EnvelopedData. Fushat e pĂ«rcaktuara identifikohen sipas asaj qĂ« quhet decode path — kjo pĂ«rcakton vendndodhjen e saktĂ« tĂ« çdo elementi nĂ« tĂ« gjitha strukturat.

Nuk gjithmonë dëshirohet ose nuk gjithmonë është e mundur që këto defines të shtohen menjëherë në skemë. Mund të ketë raste specifike për aplikacionin kur OID-të dhe strukturat dihen vetëm në një projekt të jashtëm. PyDERASN ofron mundësinë e përcaktimit të këtyre defines pikërisht në momentin e dekodimit të strukturës:

ContentInfo().decode(data, ctx={"defines_by_path": ((
    (
        "content", DecodePathDefBy(id_signedData),
        "certificates", any, "certificate", "tbsCertificate",
        "extensions", any, "extnID",
    ),
    ((("extnValue",), {
        id_ce_authorityKeyIdentifier: AuthorityKeyIdentifier(),
        id_ce_basicConstraints: BasicConstraints(),
        [...]
        id_ru_subjectSignTool: SubjectSignTool(),
    }),),
),)})

Këtu ne po themi se në CMS SignedData për të gjithë certifikatat e bashkangjitura, të dekodojmë të gjithë zgjerimet e tyre (AuthorityKeyIdentifier, BasicConstraints, SubjectSignTool, etj.). Ne caktuam përmes decode path, cilit element duhet t'i «shtojmë» defines, si të ishte caktuar në skemë.

Në fund, PyDERASN ka mundësinë e funksionimit nga linja e komandës për dekodimin e skedarëve ASN.1 dhe ka një printim të bukur. Mund të dekodoni ASN.1 të rastësishëm, ose mund të caktoni një skemë të saktë dhe të shihni diçka të ngjashme:

PyDERASN: si shkrova një bibliotekë ASN.1 me slots dhe blobs

Informacion i paraqitur: zhvendosja e objektit, gjatësia e etiketës, gjatësia e përmbajtjes, prania e EOC (fund i oktetëve), treguesi i kodimit BER, treguesi i kodimit me gjatësi të paqartë, gjatësia dhe zhvendosja e etikës EXPLICIT (nëse ka), thellësia e ndërlikimit të objektit në struktura, vlera IMPLICIT/EXPLICIT e etikës, emri i objektit sipas skemës, tipi i tij bazë ASN.1, numri rendor brenda SEQUENCE/SET OF, vlera e CHOICE (nëse ka), emri i lexueshëm për INTEGER/ENUMERATED/BIT STRING sipas skemës, vlera e çdo tipi bazë, flaka DEFAULT/OPTIONAL nga skema, treguesi nëse objekti është dekoduar automatikisht si DEFINED BY dhe përmes cilës OID ndodhi kjo, OID i lexueshëm për njeriun.

Sistema e printimit të bukur është e dizajnuar në mënyrë që të gjenerojë një seri objektesh PP, të cilat vizualizohen me mjete të veçanta. Në screenshot-in është treguar renderuesi në tekst të thjeshtë me ngjyra. Ekzistojnë gjithashtu renderues në format JSON/HTML, në mënyrë që kjo të mund të shihet me ndriçim në shfletuesin ASN.1 si në asn1js projekti.

Biblioteka të tjera

Kjo nuk ishte qëllimi, por PyDERASN doli të ishte ndjeshëm më e shpejtë se pyasn1. Për shembull, dekodimi i skedave CRL me madhësi megabajt mund të marrë kaq shumë kohë, saqë do të duhet të mendoni për formate të përkohshme ruajtjeje të dhënash (të shpejtë) dhe të ndryshoni arkitekturën e aplikacioneve. pyasn1 dekodon CRL CACert.org në laptopin tim më shumë se 20 minuta, ndërsa PyDERASN vetëm për 28 sekonda! Ekziston një projekt asn1crypto, i orientuar për punën e shpejtë me strukturat kriptografike: ai dekodon (plotësisht, jo lenç) këtë të njëjtin CRL në 29 sekonda, megjithatë consumon pothuajse dy herë më shumë memorie operativ në fillim në Python3 (983 MiB përballë 498), dhe 3.5 herë më shumë në Python2 (1677 përballë 488), ndërsa pyasn1 konsumon edhe 4.3 herë më shumë (2093 përballë 488).

asn1crypto, që përmenda, ne nuk e shqyrtuam, sepse projekti ishte ende në zhvillim, dhe ne nuk kishim dëgjuar për të. Tani gjithashtu nuk do të shikonim në drejtim të tij, sepse menjëherë zbulova se ai GeneralizedTime nuk pranon një format të rastësishëm, dhe gjatë serializimit ai heshtur heq të dhënat e sekondave. Kjo është e pranueshme për punën me certifikatat X.509, por në një rast më të përgjithshëm nuk do të ishte në rregull.

Aktualisht, PyDERASN është dekoduesi më i rreptë nga dekoduesit e lirisë Python/Go DER të njohur për mua. Në bibliotekën encoding/asn1 të Go-it tim të preferuar nuk ka një verifikim rigoroz IDENTIFIKUESI I OBJEKTIT dhe UTCTime/GeneralizedTime strings. Ndonjëherë, rigoriziteti mund të pengojë (në radhë të parë, për shkak të mbështetjes mbrapa për aplikacione të vjetra, të cilat askush nuk do t'i riparojë), prandaj në PyDERASN gjatë dekodimit mund të kaloni cilësime të ndryshme të relaksuara.

Kodi i projektit përpiqet të jetë sa më i thjeshtë. E tëra biblioteka është një skedar. Kodi është shkruar me fokus në thjeshtësinë e kuptimit, pa optimizime të tepërta të performancës dhe kodin DRY. Në të nuk ka, siç e kam thënë, mbështetje për dekodimin e plotë të UTCTime/GeneralizedTime strings, si dhe tipeve të dhënash REAL, RELATIVE OID, EXTERNAL, INSTANCE OF, EMBEDDED PDV, CHARACTER STRING. Në të gjitha rastet e tjera, personalisht nuk shoh asnjë kuptim në përdorimin e librarive të tjera në Python.

Ashtu si të gjithë projektet e mia, të tipit PyGOST, GoGOST, NNCP, GoVPN, PyDERASN është plotësisht software i lirë, i shpërndarë sipas kushteve LGPLv3+, dhe i disponueshëm për shkarkim falas. Shembujt e përdorimit janë këtu dhe në testet e PyGOST.

Sergey Matveev, shifripank, anĂ«tar i Fondit tĂ« OSS, zhvilluesi Python/Go, specialist kryesor FGUП «NTC „Atlas“.

Burimi: habr.com

Blini hosting tĂ« besueshĂ«m pĂ«r faqe interneti me mbrojtje nga DDoS, serverĂ« VPS VDS đŸ”„ Blini hosting tĂ« besueshĂ«m pĂ«r faqe interneti me mbrojtje nga DDoS, serverĂ« VPS VDS | ProHoster