# Name and PKI Utility Functions
Several top-level `synta` functions provide convenient access to DN formatting,
extension lookup, GeneralName encoding, algorithm identification, and key
introspection without constructing a full decoder pipeline.
---
## DN Formatting
### `format_dn`
```python
format_dn(name_der: bytes) -> str
```
Format a DER-encoded X.500 Name as an RFC 4514 distinguished name string.
`name_der` must be the complete TLV bytes of the Name SEQUENCE (tag + length +
value), as returned by `Certificate.issuer_raw_der` or `Certificate.subject_raw_der`.
Returns a string like `"CN=example.com, O=Example Inc, C=US"`.
Returns an empty string if `name_der` cannot be parsed.
```python,ignore
dn = synta.format_dn(cert.subject_raw_der)
print(dn) # CN=example.com, O=Example Inc, C=US
```
### `format_dn_slash`
```python
format_dn_slash(name_der: bytes) -> str
```
Format a DER-encoded X.500 Name in OpenSSL slash-separated form.
`name_der` must be the complete TLV bytes of the Name SEQUENCE (tag + length +
value), as returned by `Certificate.issuer_raw_der` or `Certificate.subject_raw_der`.
Returns a string like `"/C=US/O=Example Inc/CN=example.com"`.
Returns an empty string if `name_der` cannot be parsed.
```python,ignore
dn = synta.format_dn_slash(cert.subject_raw_der)
print(dn) # /C=US/O=Example Inc/CN=example.com
```
These two functions are the structured counterparts to `Certificate.issuer` and
`Certificate.subject` (which return RFC 4514 strings directly from the parsed
certificate object). Use them when you have raw Name DER bytes from other sources
such as `parse_general_names()` `directoryName` entries.
---
## Extension Lookup
### `find_extension_value`
```python
find_extension_value(
ext_seq_der: bytes,
oid: str | ObjectIdentifier,
Find the value bytes of an X.509v3 extension by OID.
`ext_seq_der` must be the complete DER bytes of the `Extensions` SEQUENCE (i.e. the
bytes captured by the `extensions` field of a parsed `Certificate` after the
`[3] EXPLICIT` wrapper is stripped). For the common case of looking up an extension
value in a certificate directly, prefer `Certificate.get_extension_value_der()`.
`oid` is either a dotted-decimal OID string (e.g. `"2.5.29.17"`) or an
`ObjectIdentifier` instance.
Returns the extension value bytes (the content of the `extnValue` OCTET STRING,
without the OCTET STRING TLV wrapper), or `None` if no matching extension is present.
Raises `ValueError` if `oid` is not a valid OID string.
```python,ignore
import synta
# Preferred for certificate extensions โ use get_extension_value_der directly:
san_der = cert.get_extension_value_der("2.5.29.17")
# find_extension_value is useful when you have a raw Extensions SEQUENCE DER blob
# (e.g. from a CSR or a custom structure):
csr_ext_der = ... # raw Extensions SEQUENCE DER
san_der = synta.find_extension_value(csr_ext_der, "2.5.29.17")
if san_der is not None:
for tag, content in synta.parse_general_names(san_der):
print(tag, content)
```
---
## GeneralName Encoding
### `encode_general_names`
```python
encode_general_names(entries: list[tuple[int, bytes]]) -> bytes | None
```
Encode a list of `(tag_number, value_bytes)` pairs as a DER `SEQUENCE OF GeneralName`.
`entries` must be a list of `(tag_number: int, value: bytes)` tuples in the same
format returned by `parse_general_names()`. Tag numbers follow RFC 5280 (see
`synta.general_name` for named constants).
Returns the DER-encoded `SEQUENCE OF GeneralName` bytes, or `None` if any entry
cannot be encoded. Raises `ValueError` if the input is structurally invalid (e.g.
not a list of 2-tuples).
This is the inverse of `parse_general_names()`.
```python,ignore
import synta
import synta.general_name as gn
san_der = synta.encode_general_names([
(gn.DNS_NAME, b"example.com"),
(gn.DNS_NAME, b"www.example.com"),
(gn.IP_ADDRESS, b"\xc0\xa8\x00\x01"), # 192.168.0.1
(gn.RFC822_NAME, b"admin@example.com"),
])
# san_der is a DER SEQUENCE OF GeneralName suitable for use as an extension value.
```
---
## Algorithm Identification
### `signing_algorithm_der`
```python
signing_algorithm_der(
key_oid: str | ObjectIdentifier,
hash_algo: str,
Build the DER encoding of an `AlgorithmIdentifier` for signing.
`key_oid` is the public key algorithm OID โ either a dotted-decimal string (e.g.
`"1.2.840.113549.1.1.1"` for RSA) or an `ObjectIdentifier` instance.
`hash_algo` is the hash algorithm name, e.g. `"sha256"`, `"sha384"`, or `"sha512"`.
Returns the DER bytes of the `AlgorithmIdentifier` SEQUENCE, or `None` if the key
OID is not recognised or the hash algorithm is not valid for the key type. Raises
`ValueError` if `key_oid` is not a valid OID string.
```python,ignore
import synta
# AlgorithmIdentifier DER for sha256WithRSAEncryption
alg_der = synta.signing_algorithm_der("1.2.840.113549.1.1.1", "sha256")
# Or from an ObjectIdentifier instance
alg_der = synta.signing_algorithm_der(
synta.ObjectIdentifier.from_str("1.2.840.10045.2.1"), # EC public key OID
"sha384",
)
```
---
## Key Usage
### `key_usage_bit`
```python
key_usage_bit(ku_value_bytes: bytes, bit_n: int) -> bool
```
Test whether a bit position is set in a KeyUsage BIT STRING value.
`ku_value_bytes` must be the raw value bytes of the KeyUsage BIT STRING โ the bytes
inside the OCTET STRING wrapper of the extension value, after decoding the BIT STRING
tag and length. The first byte is the unused-bits count, followed by the named-bit
flags.
`bit_n` is the named-bit index as defined in RFC 5280 ยง4.2.1.3. Named-bit constants
are available in `synta.cert` (e.g. `synta.cert.KEY_USAGE_DIGITAL_SIGNATURE == 0`).
Returns `True` if bit `bit_n` is set, `False` otherwise.
```python,ignore
import synta
ku_der = cert.get_extension_value_der("2.5.29.15")
if ku_der is not None:
# Bit 5 = keyCertSign, bit 6 = cRLSign
is_ca_cert_sign = synta.key_usage_bit(ku_der, 5)
is_crl_sign = synta.key_usage_bit(ku_der, 6)
is_dig_sig = synta.key_usage_bit(ku_der, 0)
print(f"keyCertSign={is_ca_cert_sign}, cRLSign={is_crl_sign}, digitalSignature={is_dig_sig}")
```
---
## Public Key Inspection
### `decode_public_key_info`
```python
decode_public_key_info(spki_der: bytes) -> dict
```
Decode a DER-encoded `SubjectPublicKeyInfo` into a dictionary.
`spki_der` must be the complete DER bytes of the `SubjectPublicKeyInfo` SEQUENCE TLV,
as returned by `Certificate.subject_public_key_info_der` or `PublicKey.to_der()`.
Returns a `dict` with at minimum these keys:
| `"algorithm_oid"` | `str` | Dotted OID of the public-key algorithm |
| `"key_bytes"` | `bytes` | Raw key bytes from the BIT STRING |
For RSA keys the dict additionally contains:
| `"modulus"` | `bytes` | Raw modulus bytes (may include 0x00 sign byte) |
| `"exponent"` | `int` | Public exponent (typically 65537) |
| `"bit_count"` | `int` | Key size in bits |
For EC keys the dict additionally contains:
| `"bit_count"` | `int` | Key size in bits |
| `"curve_oid"` | `str` | Dotted OID of the named curve |
| `"curve_short_name"` | `str \| None` | Short name, e.g. `"prime256v1"` |
| `"curve_nist_name"` | `str \| None` | NIST name, e.g. `"P-256"` |
Raises `ValueError` if `spki_der` cannot be parsed.
```python,ignore
import synta
spki_der = cert.subject_public_key_info_der
info = synta.decode_public_key_info(spki_der)
print(info["algorithm_oid"]) # e.g. "1.2.840.10045.2.1" for EC
print(info.get("curve_nist_name")) # "P-256"
print(info.get("bit_count")) # 256
# RSA key
rsa_info = synta.decode_public_key_info(rsa_cert.subject_public_key_info_der)
print(rsa_info["algorithm_oid"]) # "1.2.840.113549.1.1.1"
print(rsa_info["bit_count"]) # 2048
print(rsa_info["exponent"]) # 65537
```
---
## Summary table
| `format_dn(name_der)` | Name DER bytes | RFC 4514 string (`"CN=..., O=..."`) |
| `format_dn_slash(name_der)` | Name DER bytes | Slash DN (`"/C=US/..."`) |
| `find_extension_value(ext_seq_der, oid)` | Extensions SEQUENCE DER + OID | Extension value bytes or `None` |
| `encode_general_names(entries)` | `list[tuple[int, bytes]]` | GeneralNames SEQUENCE DER or `None` |
| `signing_algorithm_der(key_oid, hash_algo)` | Key OID + hash name | AlgorithmIdentifier DER or `None` |
| `key_usage_bit(ku_value_bytes, bit_n)` | KeyUsage BIT STRING value bytes + bit index | `bool` |
| `decode_public_key_info(spki_der)` | SPKI DER bytes | `dict` with algorithm and key details |
See also [GeneralName and SAN](general-name.md) for `parse_general_names()` and
`parse_name_attrs()`, [Certificate](certificate.md) for `get_extension_value_der()`,
and [PEM/DER Utilities](pem-der.md) for `pem_to_der()` and `der_to_pem()`.