synta 0.1.3

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
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
# 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
- [`synta.pkixalgs` submodule]#syntapkixalgs-submodule
  - [DssParms]#dssparms
  - [DssSigValue]#dsssigvalue
  - [EcdsaSigValue]#ecdsasigvalue
  - [ECParameters]#ecparameters
  - [OID constants (`synta.pkixalgs`)]#oid-constants-syntapkixalgs
- [`synta.ac` submodule]#syntaac-submodule
  - [AttributeCertificate]#attributecertificate
  - [OID constants (`synta.ac`)]#oid-constants-syntaac
- [`synta.crmf` submodule]#syntacrmf-submodule
  - [CertReqMessages]#certreqmessages
  - [CertReqMsg]#certreqmsg
  - [OID constants (`synta.crmf`)]#oid-constants-syntacrmf
- [`synta.cmp` submodule]#syntacmp-submodule
  - [CMPMessage]#cmpmessage
  - [OID constants (`synta.cmp`)]#oid-constants-syntacmp
- [`synta.x509` submodule]#syntax509-submodule
  - [TrustStore]#truststore
  - [VerificationPolicy]#verificationpolicy
  - [CrlStore]#crlstore
  - [verify_server_certificate]#verifyservercertificate
  - [verify_client_certificate]#verifyclientcertificate
- [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 and creation](#9-examplesexample_pkcs12py-pkcs12-archive-parsing-and-creation)
  - [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)
  - [22. [`examples/example_x509_verify.py`]../examples/example_x509_verify.py — X.509 certificate chain verification](#22-examplesexamplex509verifypy-x509-certificate-chain-verification)

<!-- 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.pkixalgs`, `synta.ac`, `synta.crmf`, `synta.cmp`; `OpensslSignatureVerifier` |
| `synta-krb5` (via `synta-python`) | `synta.krb5` submodule: `Krb5PrincipalName` + PKINIT classes |
| `synta-x509-verification` (via `synta-python`) | `synta.x509` submodule: `TrustStore`, `CrlStore`, `VerificationPolicy`, `verify_server_certificate`, `verify_client_certificate` |

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
│
├── pkixalgs                   # synta.pkixalgs submodule (RFC 3279)
│   ├── DssParms, DssSigValue, EcdsaSigValue, ECParameters
│   └── ID_DSA, ID_EC_PUBLIC_KEY, ECDSA_WITH_SHA256, PRIME256V1, ...
│
├── ac                         # synta.ac submodule (RFC 5755)
│   ├── AttributeCertificate
│   └── ID_AT_ROLE, ID_AT_CLEARANCE, ID_PE_AC_AUDIT_IDENTITY, ...
│
├── crmf                       # synta.crmf submodule (RFC 4211)
│   ├── CertReqMessages, CertReqMsg
│   └── ID_REG_CTRL_REG_TOKEN, ID_REG_CTRL_AUTHENTICATOR, ...
│
├── cmp                        # synta.cmp submodule (RFC 9810)
│   ├── CMPMessage
│   └── ID_PASSWORD_BASED_MAC, ID_DHBASED_MAC, ID_KP_CM_KGA, ...
│
└── x509                       # synta.x509 submodule (RFC 5280 / CABF path validation)
    ├── TrustStore             # trusted root CA store (DER bytes)
    ├── CrlStore               # CRL revocation checking store (DER bytes)
    ├── VerificationPolicy     # server_names, name_match, validation_time, max_chain_depth, profile
    ├── X509VerificationError  # raised on any chain or policy failure
    ├── verify_server_certificate(leaf, intermediates, store, policy, crls=None) → list[bytes]
    └── verify_client_certificate(leaf, intermediates, store, policy, crls=None) → list[bytes]
```

---

## 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. |
| `create_pkcs12(certificates: list[Certificate \| bytes], private_key: PrivateKey \| bytes = None, password: bytes = None)` | `bytes` | Build a DER-encoded PKCS#12 PFX archive. Each certificate may be a `Certificate` object or DER bytes; `private_key` may be a `PrivateKey` or DER bytes. Encryption requires the `openssl` Cargo feature. |
| `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
create_pkcs12(
    certificates: list[Certificate | bytes],
    private_key: PrivateKey | bytes | None = None,
    password: bytes | None = None,
) -> bytes
```
Build a DER-encoded PKCS#12 PFX archive.  Each element of `certificates` may be a
`Certificate` object or raw DER `bytes`; both types may appear in the same list.
`private_key` may be a `PrivateKey` object or DER-encoded PKCS#8 `bytes`.  When
`password` is `None` or omitted, the archive is created without encryption.  When
`password` is provided and the library is built with the `openssl` Cargo feature,
PBES2/PBKDF2-SHA256/AES-256-CBC with 600,000 iterations is used.  Without the
`openssl` feature, supplying a password raises `ValueError`.  `TypeError` is raised
for unrecognised element types in either `certificates` or `private_key`.

```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
```

---

## `synta.pkixalgs` submodule

RFC 3279 algorithm parameter types.  Import with `import synta.pkixalgs`.

### DssParms

DSA domain parameters (RFC 3279 §2.3.2).  Holds the `p`, `q`, `g` integers for a DSA
public key, decoded from the `parameters` field of an `AlgorithmIdentifier` whose OID
is `id-dsa`.

| Property/Method | Type | Description |
|---|---|---|
| `from_der(data)` | `DssParms` | Parse a DER-encoded `Dss-Parms` SEQUENCE |
| `to_der()` | `bytes` | DER encoding of this `Dss-Parms` SEQUENCE |
| `p` | `bytes` | Prime modulus (big-endian two's-complement) |
| `q` | `bytes` | Prime divisor |
| `g` | `bytes` | Generator |

### DssSigValue

DSA signature value (RFC 3279 §2.2.2).  Contains the `(r, s)` integer pair produced
by the DSA signing operation.

| Property/Method | Type | Description |
|---|---|---|
| `from_der(data)` | `DssSigValue` | Parse a DER-encoded `Dss-Sig-Value` SEQUENCE |
| `to_der()` | `bytes` | DER encoding |
| `r` | `bytes` | Signature integer `r` (big-endian two's-complement) |
| `s` | `bytes` | Signature integer `s` |

### EcdsaSigValue

ECDSA signature value (RFC 3279 §2.2.3, X9.62).  Contains the `(r, s)` integer pair
produced by the ECDSA signing operation.

| Property/Method | Type | Description |
|---|---|---|
| `from_der(data)` | `EcdsaSigValue` | Parse a DER-encoded `ECDSA-Sig-Value` SEQUENCE |
| `to_der()` | `bytes` | DER encoding |
| `r` | `bytes` | Signature integer `r` |
| `s` | `bytes` | Signature integer `s` |

### ECParameters

EC domain parameters CHOICE (RFC 3279 §2.3.5, X9.62).  Represents the three-arm CHOICE:
`namedCurve` (OID), `ecParameters` (explicit domain params), or `implicitlyCA` (NULL).

| Property/Method | Type | Description |
|---|---|---|
| `from_der(data)` | `ECParameters` | Parse a DER-encoded `ECParameters` CHOICE |
| `to_der()` | `bytes` | DER encoding |
| `arm` | `str` | Active arm: `"namedCurve"`, `"ecParameters"`, or `"implicitlyCA"` |
| `named_curve_oid` | `ObjectIdentifier \| None` | Named-curve OID; `None` if arm is not `"namedCurve"` |

### OID constants (`synta.pkixalgs`)

| Constant | OID | Description |
|---|---|---|
| `ID_DSA` | `1.2.840.10040.4.1` | DSA public key |
| `ID_DSA_WITH_SHA1` | `1.2.840.10040.4.3` | DSA with SHA-1 |
| `DHPUBLICNUMBER` | `1.2.840.10046.2.1` | DH public key |
| `ID_EC_PUBLIC_KEY` | `1.2.840.10045.2.1` | EC public key |
| `ECDSA_WITH_SHA1` | `1.2.840.10045.4.1` | ECDSA with SHA-1 |
| `ECDSA_WITH_SHA256` | `1.2.840.10045.4.3.2` | ECDSA with SHA-256 |
| `ECDSA_WITH_SHA384` | `1.2.840.10045.4.3.3` | ECDSA with SHA-384 |
| `ECDSA_WITH_SHA512` | `1.2.840.10045.4.3.4` | ECDSA with SHA-512 |
| `PRIME192V1` | `1.2.840.10045.3.1.1` | NIST P-192 / secp192r1 |
| `PRIME256V1` | `1.2.840.10045.3.1.7` | NIST P-256 / secp256r1 |
| `SECP224R1` | `1.3.132.0.33` | NIST P-224 |
| `SECP384R1` | `1.3.132.0.34` | NIST P-384 |
| `SECP521R1` | `1.3.132.0.35` | NIST P-521 |

---

## `synta.ac` submodule

RFC 5755 Attribute Certificate v2 types.  Import with `import synta.ac`.

### AttributeCertificate

An Attribute Certificate (AC) binds a set of attributes (roles, clearances,
service-authentication information) to a holder identified by reference to their
Public Key Certificate (PKC), without requiring re-issuance of the PKC.

| Property/Method | Type | Description |
|---|---|---|
| `from_der(data)` | `AttributeCertificate` | Parse a DER-encoded `AttributeCertificate` SEQUENCE |
| `to_der()` | `bytes` | DER encoding |
| `version` | `int` | `AttCertVersion` integer (always `1` for v2 per RFC 5755) |
| `serial_number` | `bytes` | Certificate serial number as big-endian bytes |
| `not_before` | `str` | Validity start as GeneralizedTime string, e.g. `"20240101120000Z"` |
| `not_after` | `str` | Validity end as GeneralizedTime string |
| `signature_algorithm_oid` | `ObjectIdentifier` | Signature algorithm OID |
| `signature` | `bytes` | Raw signature bytes (bit-string value, zero-byte padding stripped) |
| `holder_der` | `bytes` | DER bytes of the `Holder` SEQUENCE |
| `issuer_der` | `bytes` | DER bytes of the `AttCertIssuer` CHOICE |
| `attributes_der` | `bytes` | DER bytes of the `SEQUENCE OF Attribute` attributes field |

### OID constants (`synta.ac`)

| Constant | Description |
|---|---|
| `ID_PE_AC_AUDIT_IDENTITY` | Audit identity extension (RFC 5755 §4.4.1) |
| `ID_PE_AA_CONTROLS` | AA controls extension (RFC 5755 §4.4.2) |
| `ID_PE_AC_PROXYING` | AC proxying extension (RFC 5755 §4.4.3) |
| `ID_CE_TARGET_INFORMATION` | Target information extension (RFC 5755 §4.3.2) |
| `ID_ACA_AUTHENTICATION_INFO` | Authentication information attribute |
| `ID_ACA_ACCESS_IDENTITY` | Access identity attribute |
| `ID_ACA_CHARGING_IDENTITY` | Charging identity attribute |
| `ID_ACA_GROUP` | Group attribute |
| `ID_ACA_ENC_ATTRS` | Encrypted attributes |
| `ID_AT_ROLE` | Role attribute type |
| `ID_AT_CLEARANCE` | Clearance attribute type |

---

## `synta.crmf` submodule

RFC 4211 Certificate Request Message Format types.  Import with `import synta.crmf`.

### CertReqMessages

A batch of Certificate Request Messages (`SEQUENCE OF CertReqMsg`, RFC 4211 §3).

| Property/Method | Type | Description |
|---|---|---|
| `from_der(data)` | `CertReqMessages` | Parse a DER-encoded `CertReqMessages` SEQUENCE OF |
| `to_der()` | `bytes` | DER encoding |
| `requests` | `list[CertReqMsg]` | List of `CertReqMsg` objects |
| `__len__()` | `int` | Number of requests in the batch |
| `__iter__()` | iterator | Iterate over `CertReqMsg` objects |
| `__getitem__(index)` | `CertReqMsg` | Access a specific request by zero-based index |

### CertReqMsg

A single certificate request message (RFC 4211 §4).  Obtained by indexing or iterating
a `CertReqMessages` object.

| Property | Type | Description |
|---|---|---|
| `cert_req_id` | `int` | The `certReqId` integer identifying this request in the batch |
| `cert_template_der` | `bytes` | DER bytes of the `CertTemplate` SEQUENCE (all fields optional) |
| `popo_type` | `str \| None` | Active `ProofOfPossession` arm name, or `None` if absent; one of `"raVerified"`, `"signature"`, `"keyEncipherment"`, `"keyAgreement"` |
| `popo_der` | `bytes \| None` | DER bytes of the `ProofOfPossession` CHOICE, or `None` |
| `subject_der` | `bytes \| None` | DER bytes of the `subject` `Name` from `CertTemplate`, or `None` |
| `issuer_der` | `bytes \| None` | DER bytes of the `issuer` `Name` from `CertTemplate`, or `None` |

### OID constants (`synta.crmf`)

| Constant | Description |
|---|---|
| `ID_REG_CTRL_REG_TOKEN` | Registration token control (RFC 4211 §6.1) |
| `ID_REG_CTRL_AUTHENTICATOR` | Authenticator control (RFC 4211 §6.2) |
| `ID_REG_CTRL_PKI_PUBLICATION_INFO` | PKI publication info control (RFC 4211 §6.3) |
| `ID_REG_CTRL_PKI_ARCHIVE_OPTIONS` | PKI archive options control (RFC 4211 §6.4) |
| `ID_REG_CTRL_OLD_CERT_ID` | Old certificate ID control (RFC 4211 §6.5) |
| `ID_REG_CTRL_PROTOCOL_ENCR_KEY` | Protocol encryption key control (RFC 4211 §6.6) |
| `ID_REG_INFO_UTF8_PAIRS` | UTF-8 pairs registration info (RFC 4211 §7.1) |
| `ID_REG_INFO_CERT_REQ` | Certificate request registration info (RFC 4211 §7.2) |

---

## `synta.cmp` submodule

RFC 9810 Certificate Management Protocol v3 types.  Import with `import synta.cmp`.

### CMPMessage

A CMP `PKIMessage` (RFC 9810 §5.1) — the top-level CMP envelope carrying a `PKIHeader`
and a `PKIBody`.  Use `body_type` to identify the message type and `body_der` to decode
the body payload with the appropriate submodule.

| Property/Method | Type | Description |
|---|---|---|
| `from_der(data)` | `CMPMessage` | Parse a DER-encoded `PKIMessage` SEQUENCE |
| `to_der()` | `bytes` | DER encoding |
| `pvno` | `int` | CMP protocol version number (`pvno`; `2` for CMP v2/v3) |
| `body_type` | `str` | Active `PKIBody` arm in lowercase: `"ir"`, `"ip"`, `"cr"`, `"cp"`, `"rr"`, `"rp"`, `"pkiconf"`, `"error"`, `"certConf"`, `"genm"`, `"genp"`, etc. |
| `body_der` | `bytes \| None` | DER bytes of the `PKIBody` content; `None` for `"pkiconf"` (NULL). For `"ir"`/`"cr"` arms this is a `CertReqMessages` SEQUENCE OF |
| `sender_der` | `bytes` | DER bytes of the `sender` `GeneralName` field |
| `recipient_der` | `bytes` | DER bytes of the `recipient` `GeneralName` field |
| `transaction_id` | `bytes \| None` | `transactionID` bytes, or `None` |
| `sender_nonce` | `bytes \| None` | `senderNonce` bytes, or `None` |
| `recip_nonce` | `bytes \| None` | `recipNonce` bytes, or `None` |
| `protection_alg_oid` | `ObjectIdentifier \| None` | OID of the `protectionAlg` `AlgorithmIdentifier`, or `None` |
| `message_time` | `str \| None` | `messageTime` as a GeneralizedTime string, or `None` |

### OID constants (`synta.cmp`)

| Constant | Description |
|---|---|
| `ID_PASSWORD_BASED_MAC` | Password-based MAC algorithm (RFC 9810 Appendix D) |
| `ID_DHBASED_MAC` | DH-based MAC algorithm |
| `ID_KEM_BASED_MAC` | KEM-based MAC algorithm |
| `ID_KP_CM_KGA` | CMP key-generation authority key purpose (RFC 9810 §4) |
| `ID_REG_CTRL_ALT_CERT_TEMPLATE` | Alternate certificate template control |
| `ID_REG_CTRL_ALG_ID` | Algorithm ID control |
| `ID_REG_CTRL_RSA_KEY_LEN` | RSA key length control |

---

## `synta.x509` submodule

RFC 5280 §6 + CABF Baseline Requirements certificate chain verification.

Import as:

```python
import synta.x509 as x509
```

### TrustStore

```python
class TrustStore:
    def __init__(self, certs_der: list[bytes]) -> None: ...
    @property
    def len(self) -> int: ...
    def __repr__(self) -> str: ...
```

| Parameter | Type | Description |
|---|---|---|
| `certs_der` | `list[bytes]` | DER-encoded trusted root CA certificates (one entry per certificate) |

```python
import synta
import synta.x509 as x509

with open("roots.pem", "rb") as f:
    pem_data = f.read()
ders = synta.pem_to_der(pem_data)   # list[bytes]: one entry per PEM block
store = x509.TrustStore(ders)
print(store.len)                     # number of roots loaded
```

### VerificationPolicy

```python
class VerificationPolicy:
    def __init__(
        self,
        *,
        server_names: list[str] | None = None,
        name_match: str | None = None,
        validation_time: int | None = None,
        max_chain_depth: int = 8,
        profile: str | None = None,
    ) -> None: ...

    def __repr__(self) -> str: ...
```

| Parameter | Type | Default | Description |
|---|---|---|---|
| `server_names` | `list[str]` | `[]` | DNS hostnames or IP literals; empty = skip SAN matching |
| `name_match` | `str` | `"any"` | `"any"` — at least one name must match; `"all"` — every name must match |
| `validation_time` | `int \| None` | `None` (now) | Unix epoch seconds for validity window check |
| `max_chain_depth` | `int` | `8` | Maximum number of intermediate CAs |
| `profile` | `str \| None` | `"webpki"` | `"webpki"` (CABF BRs) or `"rfc5280"` (strict RFC 5280) |

### CrlStore

```python
class CrlStore:
    def __init__(self, crl_ders: list[bytes]) -> None: ...
    @property
    def len(self) -> int: ...
    def __repr__(self) -> str: ...
```

| Parameter | Type | Description |
|---|---|---|
| `crl_ders` | `list[bytes]` | DER-encoded CRLs (one entry per CRL) |

Pass a populated `CrlStore` to `verify_server_certificate` or `verify_client_certificate`
via the `crls` keyword argument.  Certificates whose issuing CA has no matching CRL are
treated as not-revoked (soft-fail); a well-signed, in-date CRL that lists the
certificate's serial number causes `X509VerificationError` (hard-fail).

```python
import synta
import synta.x509 as x509

# From a PEM-encoded CRL file:
crl_ders = synta.pem_to_der(open("issuing-ca.crl", "rb").read())
crl_store = x509.CrlStore(crl_ders)

# From DER directly:
crl_store = x509.CrlStore([open("issuing-ca.crl.der", "rb").read()])

store  = x509.TrustStore([root_der])
policy = x509.VerificationPolicy(server_names=["example.com"])
chain  = x509.verify_server_certificate(leaf_der, [], store, policy, crls=crl_store)
```

### verify_server_certificate

```python
def verify_server_certificate(
    leaf_der: bytes,
    intermediates_der: list[bytes],
    trust_store: TrustStore,
    policy: VerificationPolicy | None = None,
    crls: CrlStore | None = None,
) -> list[bytes]: ...
```

Returns the validated chain as `list[bytes]`, root-first (`chain[0]` is the trust anchor,
`chain[-1]` is the leaf).  Raises `X509VerificationError` if the chain cannot be built
or fails a policy check.

### verify_client_certificate

```python
def verify_client_certificate(
    leaf_der: bytes,
    intermediates_der: list[bytes],
    trust_store: TrustStore,
    policy: VerificationPolicy | None = None,
    crls: CrlStore | None = None,
) -> list[bytes]: ...
```

Like `verify_server_certificate` but enforces the `clientAuth` EKU and skips SAN matching.
The `server_names` field of `VerificationPolicy` is ignored.

| Exception | When raised |
|---|---|
| `synta.x509.X509VerificationError` | Chain cannot be built, policy check fails, or certificate is expired, untrusted, or has an invalid name |
| `synta.EOFError` | Truncated DER in `leaf_der`, `intermediates_der`, or `crl_ders` |
| `ValueError` | Malformed DER tag, length, or encoding |

---

## Exceptions

| Exception | When raised |
|---|---|
| `synta.SyntaError` | ASN.1 parse or encode failure (wraps the Rust `synta::Error`) |
| `synta.x509.X509VerificationError` | Certificate chain verification failure (see `synta.x509` submodule) |
| `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-two 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 and creation

Bindings: `load_pkcs12_certificates`, `load_pkcs12_keys`, `load_pkcs12`,
`create_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).
- Build a PFX from extracted certificates using `create_pkcs12` without a password.
- Build a password-protected PFX with `create_pkcs12` (requires `openssl` feature).
- Build a cert+key PFX bundle.
- Roundtrip: build an archive then parse it back and verify the extracted certificates.

### 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).

### 22. [`examples/example_x509_verify.py`]../examples/example_x509_verify.py — X.509 certificate chain verification

Bindings: `synta.x509.TrustStore`, `synta.x509.VerificationPolicy`,
`synta.x509.verify_server_certificate`, `synta.x509.verify_client_certificate`,
`synta.x509.X509VerificationError`.

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

- Build a self-signed root CA DER in memory with `openssl req -x509` and load it
  into a `TrustStore`; print `store.len` and `repr(store)`.
- Verify a leaf certificate signed by that root with `verify_server_certificate`;
  print the chain length and each certificate's subject with
  `synta.Certificate.from_der`.
- Demonstrate `VerificationPolicy` variants: single name, multi-name `any`, multi-name
  `all`, fixed `validation_time`, `max_chain_depth`, `profile="rfc5280"`.
- Demonstrate client certificate verification with `verify_client_certificate`.
- Show that `X509VerificationError` is raised when the trust store does not contain
  the issuer, the server name does not match the SAN, and the validation time is
  outside the validity window.