synta 0.1.1

ASN.1 parser, decoder, and encoder library with DER/BER support and C FFI
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
# Synta Python Bindings — Complete Catalog

<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of Contents**  *generated with [DocToc](https://github.com/thlorenz/doctoc)*

- [Overview]#overview
- [Module layout]#module-layout
- [Top-level `synta` module]#top-level-synta-module
  - [Constants and enumerations]#constants-and-enumerations
  - [Free functions]#free-functions
- [Decoder]#decoder
  - [Constructor]#constructor
  - [Primitive decode methods]#primitive-decode-methods
  - [Structured / container decode methods]#structured-container-decode-methods
  - [Introspection helpers]#introspection-helpers
- [Encoder]#encoder
  - [Constructor]#constructor-1
  - [Primitive encode methods — raw values]#primitive-encode-methods-raw-values
  - [Primitive encode methods — typed objects]#primitive-encode-methods-typed-objects
  - [Container / tagging encode methods]#container-tagging-encode-methods
  - [Finalisation]#finalisation
- [Primitive type classes]#primitive-type-classes
  - [Integer]#integer
  - [OctetString]#octetstring
  - [BitString]#bitstring
  - [Boolean]#boolean
  - [Real]#real
  - [Null]#null
  - [UtcTime]#utctime
  - [GeneralizedTime]#generalizedtime
  - [String types]#string-types
  - [TaggedElement]#taggedelement
  - [RawElement]#rawelement
- [ObjectIdentifier]#objectidentifier
- [Certificate]#certificate
- [CertificationRequest]#certificationrequest
- [CertificateList]#certificatelist
- [OCSPResponse]#ocspresponse
- [PKCS#7 and PKCS#12 loader functions]#pkcs7-and-pkcs12-loader-functions
- [`synta.cms` submodule]#syntacms-submodule
  - [EncryptedData]#encrypteddata
  - [Content-type OID constants]#content-type-oid-constants
  - [Content-encryption algorithm OID constants]#content-encryption-algorithm-oid-constants
- [`synta.oids` submodule]#syntaoids-submodule
  - [Algorithm OIDs]#algorithm-oids
  - [Hash algorithm OIDs]#hash-algorithm-oids
  - [SLH-DSA OIDs (FIPS 205)]#slh-dsa-oids-fips-205
  - [Prefix OIDs]#prefix-oids
  - [X.509v3 extension OIDs]#x509v3-extension-oids
  - [Extended Key Usage (EKU) OIDs]#extended-key-usage-eku-oids
  - [PKINIT OIDs (RFC 4556 / RFC 8636)]#pkinit-oids-rfc-4556-rfc-8636
  - [Microsoft PKI OIDs]#microsoft-pki-oids
  - [PKCS#9 attribute OIDs (RFC 2985 / RFC 5652 / RFC 2986 / RFC 7292)]#pkcs9-attribute-oids-rfc-2985-rfc-5652-rfc-2986-rfc-7292
  - [`synta.oids.attr` — DN attribute OIDs]#syntaoidsattr-dn-attribute-oids
- [`synta.general_name` submodule]#syntageneral_name-submodule
  - [Typical dispatch pattern]#typical-dispatch-pattern
- [`synta.krb5` submodule]#syntakrb5-submodule
  - [Principal-name type constants]#principal-name-type-constants
  - [Krb5PrincipalName]#krb5principalname
  - [PKINIT protocol classes]#pkinit-protocol-classes
    - [EncryptionKey]#encryptionkey
    - [Checksum]#checksum
    - [KDFAlgorithmId]#kdfalgorithmid
    - [IssuerAndSerialNumber]#issuerandserialnumber
    - [ExternalPrincipalIdentifier]#externalprincipalidentifier
    - [PKAuthenticator]#pkauthenticator
    - [AuthPack]#authpack
    - [PaPkAsReq]#papkasreq
    - [DHRepInfo]#dhrepinfo
    - [KDCDHKeyInfo]#kdcdhkeyinfo
    - [ReplyKeyPack]#replykeypack
    - [PaPkAsRep]#papkasrep
- [Exceptions]#exceptions
- [Example programs]#example-programs
  - [1. [`examples/example_pem_helpers.py`]../examples/example_pem_helpers.py — PEM ↔ DER conversion](#1-examplesexamplepemhelperspy-pem-der-conversion)
  - [2. [`examples/example_certificate_fields.py`]../examples/example_certificate_fields.py — All Certificate properties](#2-examplesexamplecertificatefieldspy-all-certificate-properties)
  - [3. [`examples/example_certificate_extensions.py`]../examples/example_certificate_extensions.py — Extension access and SAN parsing](#3-examplesexamplecertificateextensionspy-extension-access-and-san-parsing)
  - [4. [`examples/example_certificate_pyca.py`]../examples/example_certificate_pyca.py — PyCA interoperability](#4-examplesexamplecertificatepycapy-pyca-interoperability)
  - [5. [`examples/example_csr.py`]../examples/example_csr.py — PKCS#10 CSR parsing](#5-examplesexample_csrpy-pkcs10-csr-parsing)
  - [6. [`examples/example_crl.py`]../examples/example_crl.py — CRL parsing](#6-examplesexample_crlpy-crl-parsing)
  - [7. [`examples/example_ocsp.py`]../examples/example_ocsp.py — OCSP response parsing](#7-examplesexample_ocsppy-ocsp-response-parsing)
  - [8. [`examples/example_pkcs7.py`]../examples/example_pkcs7.py — PKCS#7 certificate bundles](#8-examplesexample_pkcs7py-pkcs7-certificate-bundles)
  - [9. [`examples/example_pkcs12.py`]../examples/example_pkcs12.py — PKCS#12 archive parsing](#9-examplesexample_pkcs12py-pkcs12-archive-parsing)
  - [10. [`examples/example_pki_blocks.py`]../examples/example_pki_blocks.py — Format-agnostic PKI reader](#10-examplesexamplepkiblockspy-format-agnostic-pki-reader)
  - [11. [`examples/example_objectidentifier.py`]../examples/example_objectidentifier.py — ObjectIdentifier constructors and operations](#11-examplesexample_objectidentifierpy-objectidentifier-constructors-and-operations)
  - [12. [`examples/example_oids_catalog.py`]../examples/example_oids_catalog.py`synta.oids` constant groups](#12-examplesexampleoidscatalogpy-syntaoids-constant-groups)
  - [13. [`examples/example_time_types.py`]../examples/example_time_types.py — UtcTime and GeneralizedTime](#13-examplesexampletimetypespy-utctime-and-generalizedtime)
  - [14. [`examples/example_integer_advanced.py`]../examples/example_integer_advanced.py — Integer edge cases and bigint](#14-examplesexampleintegeradvancedpy-integer-edge-cases-and-bigint)
  - [15. [`examples/example_string_types_advanced.py`]../examples/example_string_types_advanced.py — Alternative string constructors](#15-examplesexamplestringtypes_advancedpy-alternative-string-constructors)
  - [16. [`examples/example_decoder_advanced.py`]../examples/example_decoder_advanced.py — Advanced Decoder operations](#16-examplesexampledecoderadvancedpy-advanced-decoder-operations)
  - [17. [`examples/example_encoder_advanced.py`]../examples/example_encoder_advanced.py — Advanced Encoder operations](#17-examplesexampleencoderadvancedpy-advanced-encoder-operations)
  - [18. [`examples/example_krb5_principal.py`]../examples/example_krb5_principal.py — Kerberos principal names](#18-examplesexamplekrb5principalpy-kerberos-principal-names)
  - [19. [`examples/example_krb5_pkinit.py`]../examples/example_krb5_pkinit.py — PKINIT protocol classes](#19-examplesexamplekrb5pkinitpy-pkinit-protocol-classes)
  - [20. [`examples/example_error_handling.py`]../examples/example_error_handling.py — Exception catalogue](#20-examplesexampleerrorhandlingpy-exception-catalogue)
  - [21. [`examples/example_cms_encrypted_data.py`]../examples/example_cms_encrypted_data.py — CMS EncryptedData round-trip](#21-examplesexamplecmsencrypted_datapy-cms-encrypteddata-round-trip)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

---

## Overview

The `synta` Python package is implemented as a PyO3 extension module (`_synta.abi3.so`)
built from three Rust crates:

| Rust crate | Contributes |
|---|---|
| `synta` | `Encoding`, `Decoder`, `Encoder`, all primitive types |
| `synta-certificate` | `ObjectIdentifier`, `Certificate`, `CertificationRequest`, `CertificateList`, `OCSPResponse`, `synta.oids`, PKCS#7/12 loaders |
| `synta-krb5` (via `synta-python`) | `synta.krb5` submodule: `Krb5PrincipalName` + PKINIT classes |

The package surface is defined in `python/synta/__init__.py`, which re-exports
everything from `_synta` and makes `synta.krb5` and `synta.oids` available
without an explicit sub-import.

---

## Module layout

```
synta                          # top-level package
├── Encoding                   # enum: DER | BER | CER
├── Decoder                    # streaming ASN.1 decoder
├── Encoder                    # ASN.1 encoder
├── SyntaError                 # exception class
├── __version__                # str, e.g. "0.1.0"
│
├── Integer                    # primitive types
├── OctetString
├── ObjectIdentifier
├── BitString
├── Boolean
├── Real
├── Null
├── UtcTime
├── GeneralizedTime
├── Utf8String
├── PrintableString
├── IA5String
├── NumericString
├── TeletexString
├── VisibleString
├── GeneralString
├── UniversalString
├── BmpString
├── TaggedElement
├── RawElement
│
├── Certificate                # PKI types
├── CertificationRequest
├── CertificateList
├── OCSPResponse
│
├── pem_to_der()               # PEM helpers
├── der_to_pem()
│
├── load_der_pkcs7_certificates()   # PKCS#7 / PKCS#12 loaders
├── load_pem_pkcs7_certificates()
├── load_pkcs12_certificates()
├── load_pkcs12_keys()
├── load_pkcs12()
├── read_pki_blocks()
│
├── general_name               # synta.general_name submodule
│   ├── OTHER_NAME, RFC822_NAME, DNS_NAME, X400_ADDRESS
│   ├── DIRECTORY_NAME, EDI_PARTY_NAME, URI
│   ├── IP_ADDRESS, REGISTERED_ID
│   └── (integer tag constants for GeneralName CHOICE, RFC 5280 §4.2.1.6)
│
├── oids                       # synta.oids submodule
│   ├── RSA_ENCRYPTION, SHA256_WITH_RSA, ...
│   ├── EC_PUBLIC_KEY, EC_CURVE_P256, ...
│   ├── ED25519, ED448, ML_DSA_44, ...
│   ├── SUBJECT_ALT_NAME, BASIC_CONSTRAINTS, ...
│   ├── KP_SERVER_AUTH, KP_CLIENT_AUTH, ...
│   ├── ID_PKINIT_SAN, ID_PKINIT_KPCLIENT_AUTH, ...
│   ├── ID_MS_SAN_UPN, ID_MS_KP_SMARTCARD_LOGON, ...
│   └── attr                   # synta.oids.attr submodule
│       ├── COMMON_NAME, ORGANIZATION, COUNTRY, ...
│       └── ...
│
└── krb5                       # synta.krb5 submodule
    ├── KRB5_PRINCIPAL_NAME_OID
    ├── NT_UNKNOWN, NT_PRINCIPAL, NT_SRV_INST, ...
    ├── Krb5PrincipalName
    ├── EncryptionKey
    ├── Checksum
    ├── KDFAlgorithmId
    ├── IssuerAndSerialNumber
    ├── ExternalPrincipalIdentifier
    ├── PKAuthenticator
    ├── AuthPack
    ├── PaPkAsReq
    ├── DHRepInfo
    ├── KDCDHKeyInfo
    ├── ReplyKeyPack
    └── PaPkAsRep
```

---

## Top-level `synta` module

### Constants and enumerations

| Name | Type | Description |
|---|---|---|
| `Encoding.DER` | `Encoding` | Distinguished Encoding Rules |
| `Encoding.BER` | `Encoding` | Basic Encoding Rules |
| `Encoding.CER` | `Encoding` | Canonical Encoding Rules |
| `SyntaError` | exception class | Raised on ASN.1 parse or encode failures |
| `__version__` | `str` | Package version string (from `Cargo.toml`) |

### Free functions

| Signature | Returns | Description |
|---|---|---|
| `pem_to_der(data: bytes)` | `list[bytes]` | Decode one or more PEM blocks to DER. Always returns a list (one entry per block); no block → `ValueError`. |
| `der_to_pem(der: bytes, label: str)` | `bytes` | Wrap DER bytes in a `-----BEGIN {label}-----` / `-----END {label}-----` block. |
| `load_der_pkcs7_certificates(data: bytes)` | `list[Certificate]` | Extract certificates from a DER/BER PKCS#7 SignedData blob. |
| `load_pem_pkcs7_certificates(data: bytes)` | `list[Certificate]` | Decode PEM, then extract certificates from each PKCS#7 block. |
| `load_pkcs12_certificates(data: bytes, password: bytes = None)` | `list[Certificate]` | Extract certificates from a PKCS#12 archive. Encrypted bags require the `openssl` Cargo feature. |
| `load_pkcs12_keys(data: bytes, password: bytes = None)` | `list[bytes]` | Extract PKCS#8 private key DER blobs from a PKCS#12 archive. |
| `load_pkcs12(data: bytes, password: bytes = None)` | `tuple[list[Certificate], list[bytes]]` | Extract both certificates and keys from a PKCS#12 archive in one call. |
| `read_pki_blocks(data: bytes, password: bytes = None)` | `list[tuple[str, bytes]]` | Auto-detect format (PEM, PKCS#7, PKCS#12, raw DER) and return `(label, der_bytes)` tuples. Labels: `"CERTIFICATE"` or `"PRIVATE KEY"`. |
| `parse_general_names(san_der: bytes)` | `list[tuple[int, bytes]]` | Parse a DER `SEQUENCE OF GeneralName` into `(tag_number, content)` pairs. Use `synta.general_name` constants to dispatch on `tag_number`. |
| `parse_name_attrs(name_der: bytes)` | `list[tuple[str, str]]` | Walk a DER Name SEQUENCE and return `(dotted_oid, value_str)` pairs in traversal order. |

---

## Decoder

### Constructor

```python
Decoder(data: bytes, encoding: Encoding)
```

Creates a streaming decoder over `data`.  The internal position starts at 0.
Each `decode_*` call advances the position past the decoded element.

### Primitive decode methods

| Method | Returns | ASN.1 type | Tag |
|---|---|---|---|
| `decode_integer()` | `Integer` | INTEGER | `0x02` |
| `decode_octet_string()` | `OctetString` | OCTET STRING | `0x04` |
| `decode_oid()` | `ObjectIdentifier` | OBJECT IDENTIFIER | `0x06` |
| `decode_bit_string()` | `BitString` | BIT STRING | `0x03` |
| `decode_boolean()` | `Boolean` | BOOLEAN | `0x01` |
| `decode_utc_time()` | `UtcTime` | UTCTime | `0x17` |
| `decode_generalized_time()` | `GeneralizedTime` | GeneralizedTime | `0x18` |
| `decode_null()` | `Null` | NULL | `0x05` |
| `decode_real()` | `Real` | REAL | `0x09` |
| `decode_utf8_string()` | `Utf8String` | UTF8String | `0x0c` |
| `decode_printable_string()` | `PrintableString` | PrintableString | `0x13` |
| `decode_ia5_string()` | `IA5String` | IA5String | `0x16` |
| `decode_numeric_string()` | `NumericString` | NumericString | `0x12` |
| `decode_teletex_string()` | `TeletexString` | TeletexString / T61String | `0x14` |
| `decode_visible_string()` | `VisibleString` | VisibleString | `0x1a` |
| `decode_general_string()` | `GeneralString` | GeneralString | `0x1b` |
| `decode_universal_string()` | `UniversalString` | UniversalString | `0x1c` |
| `decode_bmp_string()` | `BmpString` | BMPString | `0x1e` |
| `decode_any()` | any Python object | any element ||
| `decode_any_str()` | `str` | any string type ||

`decode_any()` dispatches on the tag at the current position:
- SEQUENCE / SET → `list`
- known primitives → typed object (e.g. `Integer`, `Boolean`)
- tagged elements → `TaggedElement`
- unknown universal tags → `RawElement`

`decode_any_str()` reads one TLV and decodes it as a native Python `str`,
applying the correct encoding for each of the nine ASN.1 string types:

| Tag | Type | Decoding |
|-----|------|----------|
| 12 | UTF8String | UTF-8 (lossy) |
| 18 | NumericString | UTF-8 |
| 19 | PrintableString | UTF-8 |
| 20 | TeletexString / T61String | Latin-1 (each byte → U+0000–U+00FF) |
| 22 | IA5String | UTF-8 |
| 26 | VisibleString | UTF-8 |
| 27 | GeneralString | UTF-8 |
| 28 | UniversalString | UCS-4 big-endian |
| 30 | BMPString | UCS-2 big-endian |

Raises `ValueError` for any other tag; raises `EOFError` if the decoder is empty.
This is the single-call replacement for the duck-typing probe on `decode_any()`:

```python
# Before — three-way probe:
val = decoder.decode_any()
if hasattr(val, 'as_str'):
    s = val.as_str()
elif hasattr(val, 'to_bytes'):
    s = val.to_bytes().decode('latin-1')
else:
    raise ValueError(f"not a string: {type(val)}")

# After — one call, correct encoding for all nine types:
s = decoder.decode_any_str()
```

### Structured / container decode methods

| Method | Signature | Returns | Description |
|---|---|---|---|
| `decode_sequence` | `()` | `Decoder` | Consume a SEQUENCE TLV; return child decoder over its contents. |
| `decode_set` | `()` | `Decoder` | Consume a SET TLV; return child decoder over its contents. |
| `decode_explicit_tag` | `(tag_num: int)` | `Decoder` | Strip an explicit context-specific tag `[tag_num]`; return child decoder over the content. |
| `decode_implicit_tag` | `(tag_num: int, tag_class: str)` | `Decoder` | Strip an implicit tag; return child decoder over the **value bytes only** (no tag/length). `tag_class` is `"Context"`, `"Application"`, `"Private"`, or `"Universal"`. |
| `decode_raw_tlv` | `()` | `bytes` | Read the next complete TLV (tag + length + value) as raw bytes and advance past it. |

### Introspection helpers

| Method | Returns | Description |
|---|---|---|
| `peek_tag()` | `tuple[int, str, bool]` | `(tag_number, tag_class, is_constructed)` — does **not** advance the position. Raises `EOFError` if no data remains. |
| `remaining_bytes()` | `bytes` | All bytes from the current position to the end. Useful after `decode_implicit_tag` to retrieve bare primitive value bytes. |
| `is_empty()` | `bool` | `True` when the current position equals the data length. |
| `position()` | `int` | Current byte offset. |
| `remaining()` | `int` | Number of bytes left. |

---

## Encoder

### Constructor

```python
Encoder(encoding: Encoding)
```

Creates a new in-memory encoder.  Elements are appended in call order.
Call `finish()` to retrieve the accumulated bytes.

### Primitive encode methods — raw values

| Method | Signature | ASN.1 type |
|---|---|---|
| `encode_integer` | `(value: int)` | INTEGER — accepts any Python `int` (arbitrary magnitude via bigint path) |
| `encode_octet_string` | `(data: bytes)` | OCTET STRING |
| `encode_oid` | `(value: ObjectIdentifier)` | OBJECT IDENTIFIER |
| `encode_bit_string` | `(value: BitString)` | BIT STRING |
| `encode_boolean` | `(value: bool)` | BOOLEAN |
| `encode_utc_time` | `(value: UtcTime)` | UTCTime |
| `encode_generalized_time` | `(value: GeneralizedTime)` | GeneralizedTime |
| `encode_real` | `(value: float)` | REAL |
| `encode_null` | `()` | NULL |
| `encode_utf8_string` | `(value: str)` | UTF8String |
| `encode_printable_string` | `(value: str)` | PrintableString — raises `ValueError` for invalid chars |
| `encode_ia5_string` | `(value: str)` | IA5String — raises `ValueError` for non-ASCII |
| `encode_numeric_string` | `(value: str)` | NumericString — raises `ValueError` for non-digit/non-space |
| `encode_teletex_string` | `(data: bytes)` | TeletexString / T61String |
| `encode_visible_string` | `(value: str)` | VisibleString — raises `ValueError` for invalid chars |
| `encode_general_string` | `(data: bytes)` | GeneralString |
| `encode_universal_string` | `(value: str)` | UniversalString (UCS-4 BE) |
| `encode_bmp_string` | `(value: str)` | BMPString (UCS-2 BE) — raises `ValueError` for non-BMP code points |

### Primitive encode methods — typed objects

Each primitive type has an `_object` variant that accepts the corresponding
Python wrapper instead of a raw value.

| Method | Accepts |
|---|---|
| `encode_integer_object` | `Integer` |
| `encode_octet_string_object` | `OctetString` |
| `encode_oid_object` | `ObjectIdentifier` (alias for `encode_oid`) |
| `encode_bit_string_object` | `BitString` (alias for `encode_bit_string`) |
| `encode_boolean_object` | `Boolean` |
| `encode_utc_time_object` | `UtcTime` (alias for `encode_utc_time`) |
| `encode_generalized_time_object` | `GeneralizedTime` (alias for `encode_generalized_time`) |
| `encode_real_object` | `Real` |
| `encode_null_object` | `Null` |
| `encode_utf8_string_object` | `Utf8String` |
| `encode_printable_string_object` | `PrintableString` |
| `encode_ia5_string_object` | `IA5String` |
| `encode_numeric_string_object` | `NumericString` |
| `encode_teletex_string_object` | `TeletexString` |
| `encode_visible_string_object` | `VisibleString` |
| `encode_general_string_object` | `GeneralString` |
| `encode_universal_string_object` | `UniversalString` |
| `encode_bmp_string_object` | `BmpString` |

### Container / tagging encode methods

| Method | Signature | Description |
|---|---|---|
| `encode_sequence` | `(inner_bytes: bytes)` | Wrap `inner_bytes` with SEQUENCE TLV (tag `0x30`). |
| `encode_set` | `(inner_bytes: bytes)` | Wrap `inner_bytes` with SET TLV (tag `0x31`). |
| `encode_explicit_tag` | `(tag_num: int, tag_class: str, inner_bytes: bytes)` | Wrap `inner_bytes` in an explicit constructed tag. `tag_class`: `"Context"`, `"Application"`, `"Private"`. |
| `encode_implicit_tag` | `(tag_num: int, tag_class: str, is_constructed: bool, value_bytes: bytes)` | Emit an implicit tag over raw value bytes. Set `is_constructed=True` for SEQUENCE/SET underlying types. |

### Finalisation

| Method | Returns | Description |
|---|---|---|
| `finish()` | `bytes` | Consume the encoder and return the accumulated DER/BER bytes. The encoder is reset and can be reused (rarely needed). |

---

## Primitive type classes

### Integer

```python
Integer(value: int)            # constructor — i64 range only
Integer.from_bytes(data: bytes) -> Integer   # big-endian two's complement
Integer.from_u64(value: int) -> Integer      # unsigned 64-bit
```

| Method | Returns | Description |
|---|---|---|
| `to_int()` | `int` | Convert to Python `int` via i64; raises `OverflowError` if too large. |
| `to_i128()` | `int` | Convert via i128; raises `OverflowError` if too large. |
| `to_bytes()` | `bytes` | Raw big-endian two's complement bytes. |

Special methods: `__repr__`, `__str__`.

### OctetString

```python
OctetString(data: bytes)
```

| Method | Returns |
|---|---|
| `to_bytes()` | `bytes` |
| `__len__()` | `int` |
| `__eq__(other)` | `bool` |

### BitString

```python
BitString(data: bytes, unused_bits: int)   # unused_bits in 0–7
```

| Method | Returns | Description |
|---|---|---|
| `to_bytes()` | `bytes` | Raw content bytes (excluding unused-bits octet). |
| `unused_bits()` | `int` | Number of padding bits in the last byte. |
| `bit_len()` | `int` | Total significant bits (`len(data) * 8 - unused_bits`). |
| `__len__()` | `int` | Same as `bit_len()`. |
| `__eq__(other)` | `bool` | |

### Boolean

```python
Boolean(value: bool)
```

| Method | Returns |
|---|---|
| `value()` | `bool` |
| `__bool__()` | `bool` |

### Real

```python
Real(value: float)
```

| Method | Returns | Description |
|---|---|---|
| `value()` | `float` | |
| `is_infinite()` | `bool` | `True` for ±∞ |
| `is_nan()` | `bool` | `True` for NaN |
| `is_finite()` | `bool` | `True` for finite, non-NaN |
| `__float__()` | `float` | Enables `float(r)` |
| `__eq__`, `__hash__` | | Hash consistent with IEEE 754 (`NaN != NaN`, `-0.0 == 0.0`) |

### Null

```python
Null()
```

`__repr__` returns `"Null()"`. All `Null()` instances compare equal.

### UtcTime

```python
UtcTime(year: int, month: int, day: int, hour: int, minute: int, second: int)
```

Year must be in the range 1950–2049.  Raises `ValueError` on invalid input.

Properties: `year`, `month`, `day`, `hour`, `minute`, `second` (all `int`).
`__str__` returns the canonical YYMMDDHHMMSSZ form.

### GeneralizedTime

```python
GeneralizedTime(year: int, month: int, day: int, hour: int, minute: int, second: int,
                milliseconds: int | None = None)
```

Properties: `year`, `month`, `day`, `hour`, `minute`, `second` (int), `milliseconds` (`int | None`).
`__str__` returns the canonical YYYYMMDDHHMMSS[.fff]Z form.

### String types

All string types expose `.as_str() -> str` and support `__str__`, `__eq__`, `__len__`.
Types whose character sets are subsets of ASCII raise `ValueError` on construction if
invalid characters are supplied.

| Class | Constructor | Valid charset | Notes |
|---|---|---|---|
| `Utf8String` | `(value: str)` | Unicode | |
| `PrintableString` | `(value: str)` | `A–Z a–z 0–9 ' ( ) + , - . / : = ?` | |
| `IA5String` | `(value: str)` | ASCII (0x00–0x7f) | |
| `NumericString` | `(value: str)` | Digits and space | |
| `TeletexString` | `(data: bytes)` | Arbitrary bytes | Also: `TeletexString.from_latin1(str)`, `from_str(str)`. `.to_bytes()` returns raw bytes. |
| `VisibleString` | `(value: str)` | Printable ASCII (0x21–0x7e) | |
| `GeneralString` | `(data: bytes)` | Arbitrary bytes | Also: `GeneralString.from_ascii(str)` (ASCII only, raises `ValueError` for > U+007F), `from_str(str)`. `.to_bytes()` returns raw bytes. |
| `UniversalString` | `(value: str)` | Unicode (UCS-4 BE) | Also: `UniversalString.from_bytes(data: bytes)`. |
| `BmpString` | `(value: str)` | BMP only (U+0000–U+FFFF) | Also: `BmpString.from_bytes(data: bytes)`. Raises `ValueError` for non-BMP code points. |

### TaggedElement

Returned by `Decoder.decode_any()` for explicitly-tagged or application/private-tagged values.

| Attribute | Type | Description |
|---|---|---|
| `tag_number` | `int` | The tag number |
| `tag_class` | `str` | `"Universal"`, `"Context"`, `"Application"`, or `"Private"` |
| `is_constructed` | `bool` | `True` for constructed (e.g. wrapped SEQUENCE) |
| `value` | any | The inner decoded element |

### RawElement

Returned by `Decoder.decode_any()` for unknown universal tags (enables forward-compatible parsing).

| Attribute / Method | Type | Description |
|---|---|---|
| `tag_number` | `int` | |
| `tag_class` | `str` | |
| `is_constructed` | `bool` | |
| `data` | `bytes` | Raw content bytes (no tag or length) |

---

## ObjectIdentifier

```python
ObjectIdentifier(oid_str: str)                     # from dotted-decimal, e.g. "2.5.4.3"
ObjectIdentifier.from_components(comps: list[int]) # from arc list
ObjectIdentifier.from_der_value(data: bytes)       # from implicit-tag content bytes (tag+length stripped)
```

| Method / Dunder | Returns | Description |
|---|---|---|
| `components()` | `tuple[int, ...]` | OID arc components |
| `__str__()` | `str` | Dotted-decimal notation (cached) |
| `__repr__()` | `str` | `ObjectIdentifier('2.5.4.3')` |
| `__eq__(other)` | `bool` | Compares against another `ObjectIdentifier` or a dotted `str` |
| `__hash__()` | `int` | Consistent with `hash(str(oid))` so `oid in {"2.5.4.3"}` works |

`ObjectIdentifier` instances are **frozen** (immutable, thread-safe).

---

## Certificate

Represents an RFC 5280 X.509 v3 certificate.  Parsing is lazy: `from_der` performs
only a 4-operation shallow scan; the full decode happens on first field access.

```python
Certificate.from_der(data: bytes) -> Certificate
Certificate.full_from_der(data: bytes) -> Certificate   # eager: full decode at construction
Certificate.from_pem(data: bytes) -> Certificate | list[Certificate]
Certificate.to_pem(cert_or_list) -> bytes               # static method
Certificate.from_pyca(pyca_cert) -> Certificate         # requires `cryptography`
cert.to_pyca() -> cryptography.x509.Certificate         # requires `cryptography`
```

| Property | Type | Description |
|---|---|---|
| `serial_number` | `int` | Serial number as Python int (arbitrary size) |
| `version` | `int \| None` | Version field (0=v1, 1=v2, 2=v3) |
| `issuer` | `str` | RFC 4514 DN string |
| `issuer_raw_der` | `bytes` | Raw DER of issuer Name SEQUENCE |
| `subject` | `str` | RFC 4514 DN string |
| `subject_raw_der` | `bytes` | Raw DER of subject Name SEQUENCE |
| `not_before` | `str` | Validity notBefore as string |
| `not_after` | `str` | Validity notAfter as string |
| `signature_algorithm` | `str` | Algorithm name or dotted OID |
| `signature_algorithm_oid` | `ObjectIdentifier` | |
| `signature_algorithm_params` | `bytes \| None` | DER-encoded parameters or `None` |
| `signature_value` | `bytes` | Raw signature bytes |
| `public_key_algorithm` | `str` | Algorithm name or dotted OID |
| `public_key_algorithm_oid` | `ObjectIdentifier` | |
| `public_key_algorithm_params` | `bytes \| None` | DER-encoded parameters (curve OID for EC) or `None` |
| `public_key` | `bytes` | Raw subject public key bytes |
| `tbs_bytes` | `bytes` | DER bytes of TBSCertificate (the signed region) |
| `extensions_der` | `bytes \| None` | DER SEQUENCE OF Extension, or `None` for v1/v2 certs |

| Method | Signature | Returns | Description |
|---|---|---|---|
| `to_der()` | `()` | `bytes` | Original DER bytes (zero-copy) |
| `get_extension_value_der` | `(oid: str \| ObjectIdentifier)` | `bytes \| None` | Return the extnValue content bytes for the named extension OID, or `None` if absent. |
| `subject_alt_names()` | `()` | `list[tuple[int, bytes]]` | Return SAN entries as `(tag_number, content)` pairs. Use `synta.general_name` constants for dispatch. Returns `[]` when no SAN extension is present. |

All properties are cached after first access.

---

## CertificationRequest

Represents an RFC 2986 PKCS#10 Certificate Signing Request.

```python
CertificationRequest.from_der(data: bytes) -> CertificationRequest
CertificationRequest.from_pem(data: bytes) -> CertificationRequest | list[CertificationRequest]
CertificationRequest.to_pem(csr_or_list) -> bytes
```

| Property | Type | Description |
|---|---|---|
| `version` | `int` | CSR version (always 0 = v1 per RFC 2986) |
| `subject` | `str` | RFC 4514 DN string |
| `subject_raw_der` | `bytes` | Raw DER of subject Name SEQUENCE |
| `signature_algorithm` | `str` | Algorithm name or dotted OID |
| `signature_algorithm_oid` | `ObjectIdentifier` | |
| `signature` | `bytes` | Raw signature bytes |
| `public_key_algorithm` | `str` | Algorithm name or dotted OID |
| `public_key_algorithm_oid` | `ObjectIdentifier` | |
| `public_key` | `bytes` | Raw subject public key bytes |

| Method | Signature | Returns | Description |
|---|---|---|---|
| `to_der()` | `()` | `bytes` | Original DER bytes |

---

## CertificateList

Represents an RFC 5280 Certificate Revocation List.

```python
CertificateList.from_der(data: bytes) -> CertificateList
CertificateList.from_pem(data: bytes) -> CertificateList | list[CertificateList]
CertificateList.to_pem(crl_or_list) -> bytes
```

| Property | Type | Description |
|---|---|---|
| `issuer` | `str` | RFC 4514 DN string |
| `issuer_raw_der` | `bytes` | Raw DER of issuer Name SEQUENCE |
| `this_update` | `str` | thisUpdate time as string |
| `next_update` | `str \| None` | nextUpdate time as string, or `None` if absent |
| `signature_algorithm` | `str` | Algorithm name or dotted OID |
| `signature_algorithm_oid` | `ObjectIdentifier` | |
| `signature_value` | `bytes` | Raw signature bytes |
| `revoked_count` | `int` | Number of revoked certificate entries |

| Method | Signature | Returns | Description |
|---|---|---|---|
| `to_der()` | `()` | `bytes` | Original DER bytes |

---

## OCSPResponse

Represents an RFC 6960 OCSP Response (outer envelope only).

```python
OCSPResponse.from_der(data: bytes) -> OCSPResponse
OCSPResponse.from_pem(data: bytes) -> OCSPResponse | list[OCSPResponse]
OCSPResponse.to_pem(resp_or_list) -> bytes
```

| Property | Type | Description |
|---|---|---|
| `status` | `str` | Response status: `"successful"`, `"malformedRequest"`, `"internalError"`, `"tryLater"`, `"sigRequired"`, `"unauthorized"` |
| `response_type_oid` | `ObjectIdentifier \| None` | OID of the responseBytes contentType, or `None` for non-successful responses |
| `response_bytes` | `bytes \| None` | Raw content of the responseBytes OCTET STRING, or `None` |

| Method | Signature | Returns | Description |
|---|---|---|---|
| `to_der()` | `()` | `bytes` | Original DER bytes |

---

## PKCS#7 and PKCS#12 loader functions

```python
load_der_pkcs7_certificates(data: bytes) -> list[Certificate]
```
Parse a DER or BER PKCS#7 SignedData blob and return its embedded certificates.

```python
load_pem_pkcs7_certificates(data: bytes) -> list[Certificate]
```
Decode PEM block(s), then extract certificates from each PKCS#7 payload.

```python
load_pkcs12_certificates(data: bytes, password: bytes = None) -> list[Certificate]
```
Extract certificates from a PKCS#12 / PFX archive.  Pass `password=b""` or omit for
unencrypted archives.  Encrypted bags require the `openssl` Cargo feature.
Non-certificate bag types (`keyBag`, `pkcs8ShroudedKeyBag`, `crlBag`, `secretBag`)
are silently skipped.

```python
load_pkcs12_keys(data: bytes, password: bytes = None) -> list[bytes]
```
Extract PKCS#8 private keys from a PKCS#12 archive.  Returns a list of raw
DER-encoded `OneAsymmetricKey` blobs, one per `keyBag` (unencrypted) and
`pkcs8ShroudedKeyBag` (decrypted with the `openssl` Cargo feature) entry.
`certBag`, `crlBag`, and `secretBag` entries are silently skipped.

```python
load_pkcs12(data: bytes, password: bytes = None) -> tuple[list[Certificate], list[bytes]]
```
Extract both certificates and private keys from a PKCS#12 archive in a single call.
Returns `(certs, keys)` where `certs` is a `list[Certificate]` and `keys` is a
`list[bytes]` of DER-encoded PKCS#8 structures.

```python
read_pki_blocks(data: bytes, password: bytes = None) -> list[tuple[str, bytes]]
```
Auto-detect format (PEM, PKCS#7, PKCS#12, raw DER certificate) and return
`(label, der_bytes)` pairs.  Label semantics:

- PEM input: label matches the PEM block type (e.g. `"CERTIFICATE"`, `"PRIVATE KEY"`);
  PKCS#7 blocks are expanded and each embedded cert is returned as `"CERTIFICATE"`.
- Binary PKCS#7 and raw DER: always `"CERTIFICATE"`.
- Binary PKCS#12: `"CERTIFICATE"` for `certBag` entries; `"PRIVATE KEY"` for
  `keyBag` and `pkcs8ShroudedKeyBag` entries.

---

## `synta.cms` submodule

The `synta.cms` submodule provides CMS `EncryptedData` (RFC 5652 §8) support:
symmetric encryption and decryption of arbitrary content using AES-CBC.
Encryption and decryption require the `openssl` Cargo feature.

```python
from synta.cms import (
    EncryptedData,
    ID_DATA, ID_ENCRYPTED_DATA,
    ID_AES128_CBC, ID_AES192_CBC, ID_AES256_CBC,
)
```

### EncryptedData

Represents a CMS `EncryptedData` SEQUENCE (RFC 5652 §8).

```python
EncryptedData.from_der(data: bytes) -> EncryptedData
```
Parse a DER- or BER-encoded `EncryptedData` SEQUENCE.  Raises `ValueError` if
the outer SEQUENCE envelope is malformed.

```python
EncryptedData.create(
    plaintext: bytes,
    key: bytes,
    algorithm_oid: ObjectIdentifier | str,
    content_type_oid: ObjectIdentifier | str | None = None,
) -> EncryptedData
```
Encrypt `plaintext` under `key` using the cipher identified by `algorithm_oid`
and return the resulting `EncryptedData`.  A fresh random IV is generated for
every call.  `content_type_oid` defaults to `ID_DATA`
(`1.2.840.113549.1.7.1`).  Both OID arguments accept an `ObjectIdentifier`
instance or a dotted-decimal string.  Raises `NotImplementedError` if the
library was not built with the `openssl` Cargo feature.

```python
EncryptedData.decrypt(key: bytes) -> bytes
```
Decrypt the encapsulated ciphertext under `key` and return the recovered
plaintext.  Raises `ValueError` on key-length mismatch; `NotImplementedError`
if built without the `openssl` feature.

```python
EncryptedData.to_der() -> bytes
```
Return the DER encoding of this `EncryptedData` SEQUENCE (the bytes originally
passed to `from_der`, or the freshly built DER from `create`).

**Properties:**

| Property | Type | Description |
|---|---|---|
| `version` | `int` | Version integer (always `0` for RFC 5652 §8 content) |
| `content_type` | `ObjectIdentifier` | OID of the embedded content type (typically `ID_DATA`) |
| `content_encryption_algorithm_oid` | `ObjectIdentifier` | OID of the content-encryption algorithm (e.g. `ID_AES128_CBC`) |
| `content_encryption_algorithm_params` | `bytes \| None` | DER-encoded algorithm parameters; for CBC ciphers this is an OCTET STRING (`\x04\x10<iv>`) carrying the 16-byte IV |
| `encrypted_content` | `bytes \| None` | Raw ciphertext bytes (`encryptedContent [0] IMPLICIT OCTET STRING`) |
| `unprotected_attrs` | `bytes \| None` | Raw DER bytes of the `unprotectedAttrs [1] IMPLICIT` field, or `None` if absent |

### Content-type OID constants

| Constant | OID | Name |
|---|---|---|
| `ID_DATA` | `1.2.840.113549.1.7.1` | id-data |
| `ID_SIGNED_DATA` | `1.2.840.113549.1.7.2` | id-signedData |
| `ID_ENVELOPED_DATA` | `1.2.840.113549.1.7.3` | id-envelopedData |
| `ID_DIGESTED_DATA` | `1.2.840.113549.1.7.5` | id-digestedData |
| `ID_ENCRYPTED_DATA` | `1.2.840.113549.1.7.6` | id-encryptedData |
| `ID_CT_AUTH_DATA` | `1.2.840.113549.1.9.16.1.2` | id-ct-authData |

### Content-encryption algorithm OID constants

Passed as `algorithm_oid` to `EncryptedData.create`; also returned by the
`content_encryption_algorithm_oid` property.

| Constant | OID | Key length |
|---|---|---|
| `ID_AES128_CBC` | `2.16.840.1.101.3.4.1.2` | 16 bytes |
| `ID_AES192_CBC` | `2.16.840.1.101.3.4.1.22` | 24 bytes |
| `ID_AES256_CBC` | `2.16.840.1.101.3.4.1.42` | 32 bytes |

---

## `synta.oids` submodule

All constants are `ObjectIdentifier` instances (frozen, hashable).

### Algorithm OIDs

| Constant | OID | Standard |
|---|---|---|
| `RSA_ENCRYPTION` | 1.2.840.113549.1.1.1 | PKCS #1 |
| `MD5_WITH_RSA` | 1.2.840.113549.1.1.4 | PKCS #1 |
| `SHA1_WITH_RSA` | 1.2.840.113549.1.1.5 | PKCS #1 |
| `SHA256_WITH_RSA` | 1.2.840.113549.1.1.11 | RFC 4055 |
| `SHA384_WITH_RSA` | 1.2.840.113549.1.1.12 | RFC 4055 |
| `SHA512_WITH_RSA` | 1.2.840.113549.1.1.13 | RFC 4055 |
| `EC_PUBLIC_KEY` | 1.2.840.10045.2.1 | RFC 5480 |
| `ECDSA_WITH_SHA1` | 1.2.840.10045.4.1 | ANSI X9.62 |
| `ECDSA_WITH_SHA256` | 1.2.840.10045.4.3.2 | RFC 5758 |
| `ECDSA_WITH_SHA384` | 1.2.840.10045.4.3.3 | RFC 5758 |
| `ECDSA_WITH_SHA512` | 1.2.840.10045.4.3.4 | RFC 5758 |
| `ED25519` | 1.3.101.112 | RFC 8410 |
| `ED448` | 1.3.101.113 | RFC 8410 |
| `ML_DSA_44` | 2.16.840.1.101.3.4.3.17 | FIPS 204 |
| `ML_DSA_65` | 2.16.840.1.101.3.4.3.18 | FIPS 204 |
| `ML_DSA_87` | 2.16.840.1.101.3.4.3.19 | FIPS 204 |
| `ML_KEM_512` | 2.16.840.1.101.3.4.4.1 | FIPS 203 |
| `ML_KEM_768` | 2.16.840.1.101.3.4.4.2 | FIPS 203 |
| `ML_KEM_1024` | 2.16.840.1.101.3.4.4.3 | FIPS 203 |
| `EC_CURVE_P256` | 1.2.840.10045.3.1.7 | NIST P-256 |
| `EC_CURVE_P384` | 1.3.132.0.34 | NIST P-384 |
| `EC_CURVE_P521` | 1.3.132.0.35 | NIST P-521 |
| `EC_CURVE_SECP256K1` | 1.3.132.0.10 | Bitcoin curve |

### Hash algorithm OIDs

| Constant | OID | Standard |
|---|---|---|
| `SHA224` | 2.16.840.1.101.3.4.2.4 | FIPS 180-4 |
| `SHA256` | 2.16.840.1.101.3.4.2.1 | FIPS 180-4 |
| `SHA384` | 2.16.840.1.101.3.4.2.2 | FIPS 180-4 |
| `SHA512` | 2.16.840.1.101.3.4.2.3 | FIPS 180-4 |
| `SHA512_224` | 2.16.840.1.101.3.4.2.5 | FIPS 180-4 |
| `SHA512_256` | 2.16.840.1.101.3.4.2.6 | FIPS 180-4 |
| `SHA3_224` | 2.16.840.1.101.3.4.2.7 | FIPS 202 |
| `SHA3_256` | 2.16.840.1.101.3.4.2.8 | FIPS 202 |
| `SHA3_384` | 2.16.840.1.101.3.4.2.9 | FIPS 202 |
| `SHA3_512` | 2.16.840.1.101.3.4.2.10 | FIPS 202 |
| `SHAKE128` | 2.16.840.1.101.3.4.2.11 | FIPS 202 |
| `SHAKE256` | 2.16.840.1.101.3.4.2.12 | FIPS 202 |

### SLH-DSA OIDs (FIPS 205)

`SLH_DSA_SHA2_128F`, `SLH_DSA_SHA2_128S`, `SLH_DSA_SHA2_192F`, `SLH_DSA_SHA2_192S`,
`SLH_DSA_SHA2_256F`, `SLH_DSA_SHA2_256S`, `SLH_DSA_SHAKE_128F`, `SLH_DSA_SHAKE_128S`,
`SLH_DSA_SHAKE_192F`, `SLH_DSA_SHAKE_192S`, `SLH_DSA_SHAKE_256F`, `SLH_DSA_SHAKE_256S`.

### Prefix OIDs

These are prefix arcs for use with `oid.components()` rather than exact match.

| Constant | OID prefix | Covers |
|---|---|---|
| `RSA` | 1.2.840.113549.1.1 | All PKCS#1 signature algorithms |
| `ECDSA_SIG` | 1.2.840.10045.4 | All ECDSA signature algorithms |
| `ECDSA_KEY` | 1.2.840.10045.2 | EC public-key types |
| `DSA` | 1.2.840.10040.4 | DSA and DSA-with-hash algorithms |

```python
# Example: match any RSA algorithm
import synta.oids as oids
if cert.signature_algorithm_oid.components()[:len(oids.RSA.components())] == oids.RSA.components():
    print("RSA family")
```

### X.509v3 extension OIDs

| Constant | OID | RFC reference |
|---|---|---|
| `SUBJECT_ALT_NAME` | 2.5.29.17 | RFC 5280 |
| `ISSUER_ALT_NAME` | 2.5.29.18 | RFC 5280 |
| `BASIC_CONSTRAINTS` | 2.5.29.19 | RFC 5280 |
| `KEY_USAGE` | 2.5.29.15 | RFC 5280 |
| `EXTENDED_KEY_USAGE` | 2.5.29.37 | RFC 5280 |
| `SUBJECT_KEY_IDENTIFIER` | 2.5.29.14 | RFC 5280 |
| `AUTHORITY_KEY_IDENTIFIER` | 2.5.29.35 | RFC 5280 |
| `CERTIFICATE_POLICIES` | 2.5.29.32 | RFC 5280 |
| `CRL_DISTRIBUTION_POINTS` | 2.5.29.31 | RFC 5280 |
| `AUTHORITY_INFO_ACCESS` | 1.3.6.1.5.5.7.1.1 | RFC 5280 |
| `CT_PRECERT_SCTS` | 1.3.6.1.4.1.11129.2.4.2 | RFC 6962 |

### Extended Key Usage (EKU) OIDs

| Constant | OID | Use |
|---|---|---|
| `KP_SERVER_AUTH` | 1.3.6.1.5.5.7.3.1 | TLS server authentication |
| `KP_CLIENT_AUTH` | 1.3.6.1.5.5.7.3.2 | TLS client authentication |
| `KP_CODE_SIGNING` | 1.3.6.1.5.5.7.3.3 | Code signing |
| `KP_EMAIL_PROTECTION` | 1.3.6.1.5.5.7.3.4 | S/MIME |
| `KP_TIME_STAMPING` | 1.3.6.1.5.5.7.3.8 | RFC 3161 TSA |
| `KP_OCSP_SIGNING` | 1.3.6.1.5.5.7.3.9 | OCSP responder |
| `ANY_EXTENDED_KEY_USAGE` | 2.5.29.37.0 | Match any EKU |

### PKINIT OIDs (RFC 4556 / RFC 8636)

| Constant | OID | Description |
|---|---|---|
| `ID_PKINIT_SAN` | 1.3.6.1.5.2.2 | KRB5PrincipalName OtherName type-id |
| `ID_PKINIT_KPCLIENT_AUTH` | 1.3.6.1.5.2.3.4 | PKINIT client auth EKU |
| `ID_PKINIT_KPKDC` | 1.3.6.1.5.2.3.5 | PKINIT KDC EKU |
| `ID_PKINIT_AUTH_DATA` | 1.3.6.1.5.2.3.1 | PA-PK-AS-REQ content type |
| `ID_PKINIT_DHKEY_DATA` | 1.3.6.1.5.2.3.2 | DH key data content type |
| `ID_PKINIT_RKEY_DATA` | 1.3.6.1.5.2.3.3 | Reply key pack content type |
| `ID_PKINIT_KDF` | 1.3.6.1.5.2.3.6 | KDF algorithm arc (RFC 8636) |
| `ID_PKINIT_KDF_AH_SHA1` | 1.3.6.1.5.2.3.6.1 | PKINIT KDF with SHA-1 |
| `ID_PKINIT_KDF_AH_SHA256` | 1.3.6.1.5.2.3.6.2 | PKINIT KDF with SHA-256 |
| `ID_PKINIT_KDF_AH_SHA384` | 1.3.6.1.5.2.3.6.4 | PKINIT KDF with SHA-384 |
| `ID_PKINIT_KDF_AH_SHA512` | 1.3.6.1.5.2.3.6.3 | PKINIT KDF with SHA-512 |

### Microsoft PKI OIDs

| Constant | OID | Windows name |
|---|---|---|
| `ID_MS_SAN_UPN` | 1.3.6.1.4.1.311.20.2.3 | `szOID_NT_PRINCIPAL_NAME` — UPN in OtherName |
| `ID_MS_CERTIFICATE_TEMPLATE_NAME` | 1.3.6.1.4.1.311.20.2 | `szOID_CERTIFICATE_TEMPLATE_NAME` (v1) |
| `ID_MS_CERTIFICATE_TEMPLATE` | 1.3.6.1.4.1.311.21.7 | `szOID_CERTIFICATE_TEMPLATE` (v2) |
| `ID_MS_KP_SMARTCARD_LOGON` | 1.3.6.1.4.1.311.20.2.2 | `szOID_MS_KP_SMARTCARD_LOGON` EKU |
| `ID_MS_NTDS_REPLICATION` | 1.3.6.1.4.1.311.25.1 | `szOID_NTDS_REPLICATION` EKU |

### PKCS#9 attribute OIDs (RFC 2985 / RFC 5652 / RFC 2986 / RFC 7292)

These are the signed-attribute OIDs used in CMS (RFC 5652 §11), CSR request
attributes (RFC 2986), and PKCS#12 bag attributes (RFC 7292).

| Constant | OID | Description |
|---|---|---|
| `PKCS9_EMAIL_ADDRESS` | 1.2.840.113549.1.9.1 | emailAddress |
| `PKCS9_CONTENT_TYPE` | 1.2.840.113549.1.9.3 | id-contentType (CMS signed attribute) |
| `PKCS9_MESSAGE_DIGEST` | 1.2.840.113549.1.9.4 | id-messageDigest (CMS signed attribute) |
| `PKCS9_SIGNING_TIME` | 1.2.840.113549.1.9.5 | id-signingTime (CMS signed attribute) |
| `PKCS9_COUNTERSIGNATURE` | 1.2.840.113549.1.9.6 | id-countersignature |
| `PKCS9_CHALLENGE_PASSWORD` | 1.2.840.113549.1.9.7 | id-challengePassword (PKCS#10 CSR) |
| `PKCS9_EXTENSION_REQUEST` | 1.2.840.113549.1.9.14 | id-extensionRequest (PKCS#10 CSR) |
| `PKCS9_FRIENDLY_NAME` | 1.2.840.113549.1.9.20 | id-friendlyName (PKCS#12 bag attribute) |
| `PKCS9_LOCAL_KEY_ID` | 1.2.840.113549.1.9.21 | id-localKeyId (PKCS#12 bag attribute) |

### `synta.oids.attr` — DN attribute OIDs

| Constant | OID | RFC 4514 label |
|---|---|---|
| `COMMON_NAME` | 2.5.4.3 | CN |
| `ORGANIZATION` | 2.5.4.10 | O |
| `ORG_UNIT` | 2.5.4.11 | OU |
| `COUNTRY` | 2.5.4.6 | C |
| `STATE` | 2.5.4.8 | ST |
| `LOCALITY` | 2.5.4.7 | L |
| `STREET` | 2.5.4.9 | street |
| `SERIAL_NUMBER` | 2.5.4.5 | serialNumber |
| `EMAIL_ADDRESS` | 1.2.840.113549.1.9.1 | emailAddress |
| `GIVEN_NAME` | 2.5.4.42 | givenName |
| `SURNAME` | 2.5.4.4 | SN |
| `TITLE` | 2.5.4.12 | title |
| `INITIALS` | 2.5.4.43 | initials |
| `ORG_IDENTIFIER` | 2.5.4.97 | organizationIdentifier |
| `USER_ID` | 0.9.2342.19200300.100.1.1 | uid |
| `DOMAIN_COMPONENT` | 0.9.2342.19200300.100.1.25 | dc |

---

## `synta.general_name` submodule

Integer constants for the `GeneralName` CHOICE type (RFC 5280 §4.2.1.6).
These are the `tag_number` values returned by `Certificate.subject_alt_names()`
and `synta.parse_general_names()`.

```python
import synta.general_name as gn
```

| Constant | Value | `GeneralName` alternative | Content |
|---|---|---|---|
| `OTHER_NAME` | 0 | `otherName` | Full `OtherNameValue` TLV (constructed) |
| `RFC822_NAME` | 1 | `rfc822Name` | Raw IA5String bytes (e-mail address) |
| `DNS_NAME` | 2 | `dNSName` | Raw IA5String bytes (DNS host name) |
| `X400_ADDRESS` | 3 | `x400Address` | (rarely used) |
| `DIRECTORY_NAME` | 4 | `directoryName` | Complete Name SEQUENCE TLV — pass to `parse_name_attrs()` |
| `EDI_PARTY_NAME` | 5 | `ediPartyName` | (rarely used) |
| `URI` | 6 | `uniformResourceIdentifier` | Raw IA5String bytes (URI) |
| `IP_ADDRESS` | 7 | `iPAddress` | 4 bytes (IPv4) or 16 bytes (IPv6) |
| `REGISTERED_ID` | 8 | `registeredID` | Raw OID value bytes |

### Typical dispatch pattern

```python
import ipaddress
import synta
import synta.general_name as gn

for tag_num, content in cert.subject_alt_names():
    if tag_num == gn.DNS_NAME:
        print("DNS:", content.decode("ascii"))
    elif tag_num == gn.IP_ADDRESS:
        print("IP:", ipaddress.ip_address(content))
    elif tag_num == gn.RFC822_NAME:
        print("email:", content.decode("ascii"))
    elif tag_num == gn.URI:
        print("URI:", content.decode("ascii"))
    elif tag_num == gn.DIRECTORY_NAME:
        attrs = synta.parse_name_attrs(content)   # [(oid_str, value_str), …]
        print("DirName:", attrs)
```

The same constants apply when calling `synta.parse_general_names(san_der)` directly
on raw extnValue bytes obtained from `cert.get_extension_value_der(synta.oids.SUBJECT_ALT_NAME)`.

---

## `synta.krb5` submodule

### Principal-name type constants

Integer constants from RFC 4120 §6.2 and later:

| Constant | Value | Description |
|---|---|---|
| `NT_UNKNOWN` | 0 | Unknown |
| `NT_PRINCIPAL` | 1 | User/host principal |
| `NT_SRV_INST` | 2 | Service + instance (e.g. `krbtgt`) |
| `NT_SRV_HST` | 3 | Service + hostname |
| `NT_SRV_XHST` | 4 | Service + host (remaining components) |
| `NT_UID` | 5 | Unique ID |
| `NT_X500_PRINCIPAL` | 6 | Encoded X.500 DN |
| `NT_SMTP_NAME` | 7 | SMTP email address |
| `NT_ENTERPRISE` | 10 | Enterprise (UPN-style), RFC 6806 |
| `NT_WELLKNOWN` | 11 | Well-known (anonymous), RFC 8062 |
| `NT_SRV_HST_DOMAIN` | 12 | Host-based service, Windows MS-SFU |

Also: `KRB5_PRINCIPAL_NAME_OID` — `ObjectIdentifier("1.3.6.1.5.2.2")` — the
`id-pkinit-san` OID for `KRB5PrincipalName` OtherName entries.

### Krb5PrincipalName

RFC 4556 §3.2.2 `KRB5PrincipalName` SEQUENCE.

```python
Krb5PrincipalName(realm: str, name_type: int, components: list[str])
Krb5PrincipalName.from_der(data: bytes) -> Krb5PrincipalName
```

All string arguments must be ASCII; raises `ValueError` otherwise.

| Attribute / Method | Type / Returns | Description |
|---|---|---|
| `realm` | `str` | Kerberos realm (e.g. `"EXAMPLE.COM"`) |
| `name_type` | `int` | One of the `NT_*` constants |
| `components` | `list[str]` | Name-string components |
| `to_der()` | `bytes` | DER encode the `KRB5PrincipalName` SEQUENCE |
| `__repr__`, `__eq__` | | |

### PKINIT protocol classes

All PKINIT classes are **frozen** (immutable).  Each class provides a
`from_der(data: bytes)` static method for parsing, and a `to_der()` method
for serialisation (where the encoding is well-defined).

#### EncryptionKey

RFC 3961 §2 `EncryptionKey`.

| Property | Type |
|---|---|
| `key_type` | `int` — encryption type (etype) |
| `key_value` | `bytes` — raw key material |

```python
EncryptionKey.from_der(data: bytes) -> EncryptionKey
```

#### Checksum

RFC 3961 §4 `Checksum`.

| Property | Type |
|---|---|
| `checksum_type` | `int` — checksum type |
| `checksum` | `bytes` — raw checksum bytes |

```python
Checksum.from_der(data: bytes) -> Checksum
```

#### KDFAlgorithmId

RFC 8636 §3.1 KDF algorithm identifier.

| Property | Type |
|---|---|
| `oid` | `ObjectIdentifier` — KDF algorithm OID |

```python
KDFAlgorithmId.from_der(data: bytes) -> KDFAlgorithmId
```

#### IssuerAndSerialNumber

RFC 4556 §3.2.2 certificate identifier.

| Property | Type |
|---|---|
| `issuer_raw_der` | `bytes` — DER of issuer Name SEQUENCE |
| `serial_number` | `bytes` — raw big-endian serial number bytes |

```python
IssuerAndSerialNumber.from_der(data: bytes) -> IssuerAndSerialNumber
```

#### ExternalPrincipalIdentifier

RFC 4556 §3.2.2 — identifies a client certificate by one of three optional methods.

| Property | Type |
|---|---|
| `subjectName` | `bytes \| None` — DER of subject Name |
| `issuerAndSerialNumber` | `bytes \| None` — DER of IssuerAndSerialNumber |
| `subjectKeyIdentifier` | `bytes \| None` — raw SKI bytes |

```python
ExternalPrincipalIdentifier.from_der(data: bytes) -> ExternalPrincipalIdentifier
```

#### PKAuthenticator

RFC 4556 §3.2.1 — client proof of liveness in AS-REQ.

| Property | Type |
|---|---|
| `cusec` | `int` — microseconds component of client time |
| `ctime` | `str` — client time as string |
| `nonce` | `int` — nonce value |
| `paChecksum` | `bytes \| None` — SHA-1 checksum of AS-REQ |
| `freshnessToken` | `bytes \| None` — RFC 8070 freshness token |

```python
PKAuthenticator.from_der(data: bytes) -> PKAuthenticator
```

#### AuthPack

RFC 4556 §3.2.1 — the content type signed by the client.

| Property | Type |
|---|---|
| `pkAuthenticator` | `PKAuthenticator` |
| `clientPublicValue` | `bytes \| None` — client DH public key (SubjectPublicKeyInfo DER) |
| `supportedCMSTypes` | `list[bytes]` — list of AlgorithmIdentifier DER blobs |
| `clientDHNonce` | `bytes \| None` — client DH nonce |
| `supportedKDFs` | `list[KDFAlgorithmId] \| None` — RFC 8636 KDF list |

```python
AuthPack.from_der(data: bytes) -> AuthPack
```

#### PaPkAsReq

RFC 4556 §3.2.2 — PKINIT pre-authentication request.

| Property | Type |
|---|---|
| `signed_auth_pack` | `bytes` — SignedData DER (contains `AuthPack`) |
| `trusted_certifiers` | `list[ExternalPrincipalIdentifier] \| None` |
| `kdc_pk_id` | `bytes \| None` — raw SKI bytes identifying the KDC certificate |

```python
PaPkAsReq.from_der(data: bytes) -> PaPkAsReq
```

#### DHRepInfo

RFC 4556 §3.2.4 — KDC Diffie-Hellman reply data.

| Property | Type |
|---|---|
| `dh_signed_data` | `bytes` — SignedData DER (contains `KDCDHKeyInfo`) |
| `server_dh_nonce` | `bytes \| None` — KDC DH nonce |

```python
DHRepInfo.from_der(data: bytes) -> DHRepInfo
```

#### KDCDHKeyInfo

RFC 4556 §3.2.4 — KDC DH public key and nonce.

| Property | Type |
|---|---|
| `subjectPublicKey` | `bytes` — KDC DH public key bits |
| `nonce` | `int` — nonce value |
| `dhKeyExpiration` | `str \| None` — optional expiry time |

```python
KDCDHKeyInfo.from_der(data: bytes) -> KDCDHKeyInfo
```

#### ReplyKeyPack

RFC 4556 §3.2.3 — session key and checksum from KDC (Diffie-Hellman-less path).

| Property | Type |
|---|---|
| `replyKey` | `EncryptionKey` — the session key |
| `asChecksum` | `Checksum` — checksum over the AS-REQ |

```python
ReplyKeyPack.from_der(data: bytes) -> ReplyKeyPack
```

#### PaPkAsRep

RFC 4556 §3.2.4 — PKINIT pre-authentication reply (CHOICE type).

| Property | Type |
|---|---|
| `variant` | `str``"dhInfo"` or `"encKeyPack"` |
| `value` | `bytes` — DER of the chosen alternative |

```python
PaPkAsRep.from_der(data: bytes) -> PaPkAsRep
```

---

## Exceptions

| Exception | When raised |
|---|---|
| `synta.SyntaError` | ASN.1 parse or encode failure (wraps the Rust `synta::Error`) |
| `ValueError` | Invalid arguments (e.g. invalid OID string, bad charset for PrintableString, wrong password format) |
| `OverflowError` | `Integer.to_int()` / `to_i128()` when the value does not fit |
| `EOFError` | `Decoder.peek_tag()` when no data remains |
| `ImportError` | `Certificate.to_pyca()` / `from_pyca()` when `cryptography` is not installed |

---

## Example programs

Twenty-one runnable programs in `examples/` exercise every binding documented
above.  Each program is self-contained and runs with `uv run python3
examples/example_<name>.py` from the repository root.

### 1. [`examples/example_pem_helpers.py`]../examples/example_pem_helpers.py — PEM ↔ DER conversion

Bindings: `pem_to_der`, `der_to_pem`, `Certificate.from_pem`, `Certificate.to_pem`,
`CertificationRequest.from_pem`, `CertificationRequest.to_pem`,
`CertificateList.from_pem`, `CertificateList.to_pem`.

- Round-trip a single PEM certificate block through `pem_to_der` / `der_to_pem` (`pem_to_der` always returns `list[bytes]`).
- Show `pem_to_der` with a multi-block PEM chain.
- Use `Certificate.from_pem` on a single block and on a two-certificate chain.
- Use `Certificate.to_pem` on a single cert and a list of certs.

### 2. [`examples/example_certificate_fields.py`]../examples/example_certificate_fields.py — All Certificate properties

Bindings: `Certificate.from_der`, `Certificate.full_from_der`, all `Certificate`
properties (`serial_number`, `version`, `issuer`, `issuer_raw_der`, `subject`,
`subject_raw_der`, `not_before`, `not_after`, `signature_algorithm`,
`signature_algorithm_oid`, `signature_algorithm_params`, `signature_value`,
`public_key_algorithm`, `public_key_algorithm_oid`, `public_key_algorithm_params`,
`public_key`, `tbs_bytes`), and `Certificate.to_der()` method.

- Parse the same certificate with `from_der` (lazy) and `full_from_der` (eager).
- Print every property with its Python type.
- Verify `to_der()` round-trip (re-parse the returned bytes).
- Show `signature_algorithm_params` is `None` for Ed25519 and non-`None` for RSA.

### 3. [`examples/example_certificate_extensions.py`]../examples/example_certificate_extensions.py — Extension access and SAN parsing

Bindings: `Certificate.subject_alt_names`, `Certificate.extensions_der`,
`Certificate.get_extension_value_der`, `synta.general_name` tag constants,
`synta.parse_general_names`, `synta.parse_name_attrs`,
`synta.oids.SUBJECT_ALT_NAME`, `synta.oids.BASIC_CONSTRAINTS`,
`synta.oids.SUBJECT_KEY_IDENTIFIER`, `Decoder.decode_sequence`, `Decoder.peek_tag`,
`Decoder.decode_implicit_tag`, `Decoder.decode_explicit_tag`,
`Decoder.remaining_bytes`, `Decoder.decode_raw_tlv`, `Decoder.is_empty`.

- Call `cert.subject_alt_names()` for high-level SAN access; dispatch on
  `synta.general_name` constants (`gn.DNS_NAME`, `gn.IP_ADDRESS`, etc.);
  use `ipaddress.ip_address(content)` for IP rendering.
- Verify that a certificate without a SAN extension returns an empty list.
- Access `extensions_der` and iterate the raw extension TLVs.
- Look up individual extensions by `get_extension_value_der`.
- Parse SAN entries manually with `peek_tag` / `decode_implicit_tag`
  as a lower-level alternative to `subject_alt_names()`.
- Demonstrate `peek_tag` for CHOICE dispatch; `remaining_bytes` for primitive implicit values.
- Look up BasicConstraints and decode the cA BOOLEAN.

### 4. [`examples/example_certificate_pyca.py`]../examples/example_certificate_pyca.py — PyCA interoperability

Bindings: `Certificate.to_pyca`, `Certificate.from_pyca`.

- Parse a DER certificate with synta, then call `.to_pyca()` for cryptographic operations.
- Load a PyCA certificate, convert to synta with `from_pyca()`, and compare fields.
- Show `ImportError` message when `cryptography` is absent (caught and printed).

### 5. [`examples/example_csr.py`]../examples/example_csr.py — PKCS#10 CSR parsing

Bindings: `CertificationRequest.from_der`, `CertificationRequest.from_pem`,
`CertificationRequest.to_pem`, and all `CertificationRequest` properties.

- Parse a CSR from DER and print every field.
- Round-trip through PEM with `from_pem` / `to_pem`.
- Verify `subject_raw_der` by re-decoding it as a raw Name SEQUENCE.

### 6. [`examples/example_crl.py`]../examples/example_crl.py — CRL parsing

Bindings: `CertificateList.from_der`, `CertificateList.from_pem`,
`CertificateList.to_pem`, and all `CertificateList` properties.

- Parse a CRL and print issuer, dates, algorithm, revoked count.
- Show `next_update` is `None` for CRLs that omit the field.
- Round-trip through `to_pem` / `from_pem`.

### 7. [`examples/example_ocsp.py`]../examples/example_ocsp.py — OCSP response parsing

Bindings: `OCSPResponse.from_der`, `OCSPResponse.from_pem`, `OCSPResponse.to_pem`,
and all `OCSPResponse` properties.

- Parse a successful OCSP response; print `status`, `response_type_oid`, length of `response_bytes`.
- Parse a non-successful response (e.g. `tryLater`); confirm `response_bytes` is `None`.
- Round-trip through `to_pem` / `from_pem`.

### 8. [`examples/example_pkcs7.py`]../examples/example_pkcs7.py — PKCS#7 certificate bundles

Bindings: `load_der_pkcs7_certificates`, `load_pem_pkcs7_certificates`.

- Load a `.p7b` file and print the subject of each extracted certificate.
- Demonstrate PEM-encoded PKCS#7 with `load_pem_pkcs7_certificates`.
- Show `ValueError` for non-PKCS#7 input.

### 9. [`examples/example_pkcs12.py`]../examples/example_pkcs12.py — PKCS#12 archive parsing

Bindings: `load_pkcs12_certificates`, `load_pkcs12_keys`, `load_pkcs12`.

- Parse a password-less PKCS#12 file; print subjects of extracted certificates.
- Extract private keys using `load_pkcs12_keys`; show raw PKCS#8 DER length.
- Extract both with `load_pkcs12`; show the `(certs, keys)` tuple.
- Parse an AES-256-CBC encrypted PKCS#12 with a password.
- Show `ValueError` for wrong password (encrypted case, with `openssl` feature).

### 10. [`examples/example_pki_blocks.py`]../examples/example_pki_blocks.py — Format-agnostic PKI reader

Bindings: `read_pki_blocks`.

- Pass PEM, DER, PKCS#7, and PKCS#12 bytes to `read_pki_blocks` and print the
  `(label, len(der))` tuples returned.
- Show PKCS#12 password handling.

### 11. [`examples/example_objectidentifier.py`]../examples/example_objectidentifier.py — ObjectIdentifier constructors and operations

Bindings: `ObjectIdentifier(str)`, `ObjectIdentifier.from_components`,
`ObjectIdentifier.from_der_value`, `ObjectIdentifier.components`,
`ObjectIdentifier.__eq__`, `ObjectIdentifier.__hash__`,
`Decoder.decode_oid`, `Encoder.encode_oid`, `Encoder.encode_oid_object`.

- Construct OIDs via all three constructors; verify they compare equal.
- Show `__eq__` working against a dotted string.
- Use OIDs as dict keys (demonstrate hashability).
- Round-trip through `encode_oid` / `decode_oid`.
- Show `from_der_value` with the raw content bytes from an implicit-tag context.

### 12. [`examples/example_oids_catalog.py`]../examples/example_oids_catalog.py`synta.oids` constant groups

Bindings: every constant in `synta.oids` and `synta.oids.attr`,
plus the helper functions `identify_signature_algorithm`,
`identify_public_key_algorithm`.

- Print algorithm OIDs (RSA, EC, EdDSA, ML-DSA, ML-KEM).
- Print hash OIDs (SHA-2, SHA-3).
- Print SLH-DSA OIDs.
- Print prefix OIDs and demonstrate `components()`-based prefix matching.
- Print X.509v3 extension OIDs.
- Print EKU OIDs.
- Print PKINIT OIDs.
- Print MS PKI OIDs.
- Print all nine PKCS#9 attribute OIDs (`PKCS9_EMAIL_ADDRESS`, `PKCS9_CONTENT_TYPE`,
  `PKCS9_MESSAGE_DIGEST`, `PKCS9_SIGNING_TIME`, `PKCS9_COUNTERSIGNATURE`,
  `PKCS9_CHALLENGE_PASSWORD`, `PKCS9_EXTENSION_REQUEST`, `PKCS9_FRIENDLY_NAME`,
  `PKCS9_LOCAL_KEY_ID`).
- Print every `synta.oids.attr` DN attribute OID with its RFC 4514 label.

### 13. [`examples/example_time_types.py`]../examples/example_time_types.py — UtcTime and GeneralizedTime

Bindings: `UtcTime(…)`, `UtcTime` properties (`year`, `month`, `day`, `hour`,
`minute`, `second`), `GeneralizedTime(…)`, `GeneralizedTime` properties,
`Encoder.encode_utc_time`, `Encoder.encode_utc_time_object`,
`Encoder.encode_generalized_time`, `Encoder.encode_generalized_time_object`,
`Decoder.decode_utc_time`, `Decoder.decode_generalized_time`.

- Construct both time types and inspect every property.
- Round-trip each through encode / decode; verify string representations.
- Show millisecond sub-second precision on `GeneralizedTime`.
- Show `ValueError` for out-of-range UTCTime year (< 1950 or > 2049).
- Demonstrate `encode_utc_time_object` and `encode_generalized_time_object` variants.

### 14. [`examples/example_integer_advanced.py`]../examples/example_integer_advanced.py — Integer edge cases and bigint

Bindings: `Integer(int)`, `Integer.from_bytes`, `Integer.from_u64`,
`Integer.to_int`, `Integer.to_i128`, `Integer.to_bytes`,
`Encoder.encode_integer` (bigint path), `Encoder.encode_integer_object`.

- Construct integers via all three constructors.
- Show `to_int()` succeeds for small values; raises `OverflowError` for 20-byte serials.
- Use `to_i128()` for up to 16-byte values (i128 max = 2¹²⁷−1); show `OverflowError` beyond that.
- Use `to_bytes()` for arbitrary-precision big-endian representation.
- Encode a 20-byte certificate serial number via `encode_integer(large_python_int)`.
- Verify `encode_integer_object` round-trip.

### 15. [`examples/example_string_types_advanced.py`]../examples/example_string_types_advanced.py — Alternative string constructors

Bindings: `TeletexString.from_latin1`, `TeletexString.from_str`,
`GeneralString.from_ascii`, `GeneralString.from_str`,
`UniversalString.from_bytes`, `BmpString.from_bytes`,
plus `to_bytes()` / `as_str()` on each.

- Construct `TeletexString` from bytes and Latin-1 strings; `GeneralString` from bytes and ASCII strings.
- Construct `UniversalString` and `BmpString` from raw UCS-4/UCS-2 byte buffers.
- Show `ValueError` when non-BMP code points are passed to `BmpString`.
- Round-trip each through the encoder / decoder.

### 16. [`examples/example_decoder_advanced.py`]../examples/example_decoder_advanced.py — Advanced Decoder operations

Bindings: `Decoder.decode_set`, `Decoder.peek_tag`, `Decoder.decode_raw_tlv`,
`Decoder.remaining_bytes`, `Decoder.decode_implicit_tag`, `Decoder.position`,
`Decoder.remaining`, `Decoder.is_empty`, `Decoder.decode_any_str`.

- Build a hand-crafted SET and decode it with `decode_set`.
- Use `peek_tag` in a loop to drive CHOICE dispatch.
- Capture unknown elements with `decode_raw_tlv`.
- Use `decode_implicit_tag` + `remaining_bytes` to decode a primitive implicit type
  (e.g. `[2] IMPLICIT IA5String` for a dNSName GeneralName).
- Show `position()` and `remaining()` advancing through multi-element input.
- Use `decode_any_str()` to decode a mixed-string SEQUENCE without tag inspection.

### 17. [`examples/example_encoder_advanced.py`]../examples/example_encoder_advanced.py — Advanced Encoder operations

Bindings: `Encoder.encode_implicit_tag`, `Encoder.encode_set`,
`Encoder.encode_explicit_tag`, `Encoder.encode_sequence`,
and all `_object` variants not demonstrated elsewhere.

- Build a SET containing two PrintableStrings using `encode_set`.
- Encode an implicit context tag `[2] IMPLICIT IA5String` (dNSName).
- Encode a nested structure: SEQUENCE { [0] EXPLICIT SEQUENCE { INTEGER } }.
- Demonstrate every `_object` encode variant with a typed object sourced from a decode.
- Show `ValueError` for unknown tag class strings.

### 18. [`examples/example_krb5_principal.py`]../examples/example_krb5_principal.py — Kerberos principal names

Bindings: `synta.krb5.Krb5PrincipalName`, `synta.krb5.KRB5_PRINCIPAL_NAME_OID`,
and every `NT_*` constant.

- Construct `Krb5PrincipalName` instances for each name type (`NT_PRINCIPAL`,
  `NT_SRV_INST`, `NT_SRV_HST`, `NT_ENTERPRISE`, `NT_WELLKNOWN`).
- Encode each with `to_der()` and decode back with `from_der()`.
- Verify realm, name_type, and components survive the round-trip.
- Show `__eq__` and `__repr__`.
- Print `KRB5_PRINCIPAL_NAME_OID` and demonstrate it matches `synta.oids.ID_PKINIT_SAN`.
- Show `ValueError` for non-ASCII realm or component.

### 19. [`examples/example_krb5_pkinit.py`]../examples/example_krb5_pkinit.py — PKINIT protocol classes

Bindings: `EncryptionKey`, `Checksum`, `KDFAlgorithmId`, `IssuerAndSerialNumber`,
`ExternalPrincipalIdentifier`, `PKAuthenticator`, `AuthPack`, `PaPkAsReq`,
`DHRepInfo`, `KDCDHKeyInfo`, `ReplyKeyPack`, `PaPkAsRep`.

For each class: parse hand-crafted DER bytes with `from_der`, access every property,
and print a summary of key values.

### 20. [`examples/example_error_handling.py`]../examples/example_error_handling.py — Exception catalogue

Bindings: `synta.SyntaError`, `ValueError`, `OverflowError`, `EOFError`.

- Inspect `SyntaError` as a module exception class (MRO, `issubclass` check).
- Demonstrate `EOFError` from empty input, tag-only input, and truncated value in `Decoder`.
- Demonstrate `ValueError` from tag mismatch (decoding BOOLEAN as INTEGER).
- Demonstrate `ValueError` from DER constraint violations (non-canonical BOOLEAN, non-minimal INTEGER).
- Demonstrate `OverflowError` from `Integer.to_int()` and `to_i128()` on values exceeding the target type.
- Demonstrate `ValueError` from constructor validation: `BmpString` with a non-BMP character,
  `GeneralizedTime` with an invalid month, `ObjectIdentifier` with a malformed string,
  `Krb5PrincipalName` with a non-ASCII realm, `GeneralString.from_ascii` with a non-ASCII character.

### 21. [`examples/example_cms_encrypted_data.py`]../examples/example_cms_encrypted_data.py — CMS EncryptedData round-trip

Bindings: `synta.cms.EncryptedData`, `synta.cms.ID_AES128_CBC`,
`synta.cms.ID_AES192_CBC`, `synta.cms.ID_AES256_CBC`.

Requires the `openssl` Cargo feature (`maturin develop --features openssl`).

- Create an `EncryptedData` with `EncryptedData.create` (AES-128-CBC) and inspect
  all properties: `version`, `content_type`, `content_encryption_algorithm_oid`,
  `content_encryption_algorithm_params` (IV extraction), `encrypted_content`.
- Decrypt → replace text in plaintext → re-encrypt with a fresh random IV;
  verify the round-trip with `to_der()` / `from_der()`.
- Encrypt with each of AES-128/192/256-CBC using `ID_AES128_CBC`,
  `ID_AES192_CBC`, `ID_AES256_CBC`; confirm random IV differs across calls.
- Verify synta-produced ciphertext with `openssl enc -d` (synta → openssl
  interop).
- Inspect the `EncryptedData` DER structure with `openssl asn1parse`.
- Encrypt raw bytes with `openssl enc -e`, wrap in an `EncryptedData` DER
  by hand, parse with `from_der`, and decrypt with synta (openssl → synta
  interop).