# CRMF Messages
`synta.crmf` provides RFC 4211 Certificate Request Message Format types used in CMP
certificate management.
```python
import synta.crmf as crmf
```
## CertReqMessages
A batch of Certificate Request Messages (`SEQUENCE OF CertReqMsg`, RFC 4211 §3).
```python
class CertReqMessages:
@staticmethod
def from_der(data: bytes) -> CertReqMessages: ...
def to_der(self) -> bytes: ...
requests: list[CertReqMsg]
def __len__(self) -> int: ...
def __iter__(self): ...
def __getitem__(self, index: int) -> CertReqMsg: ...
```
## CertReqMsg
A single certificate request message (RFC 4211 §4).
```python
class CertReqMsg:
cert_req_id: int # certReqId integer
cert_template_der: bytes # DER bytes of the CertTemplate SEQUENCE
popo_type: str | None # Active ProofOfPossession arm name, or None
# One of: "raVerified", "signature", "keyEncipherment", "keyAgreement"
popo_der: bytes | None # DER bytes of the ProofOfPossession CHOICE
subject_der: bytes | None # DER bytes of subject Name from CertTemplate
issuer_der: bytes | None # DER bytes of issuer Name from CertTemplate
```
## CertReqMsgBuilder
Fluent builder for a single `CertReqMsg`.
```python
class CertReqMsgBuilder:
def __init__(self) -> None: ...
def cert_req_id(self, id: int) -> CertReqMsgBuilder: ...
def subject_name(self, name_der: bytes) -> CertReqMsgBuilder: ...
def issuer_name(self, name_der: bytes) -> CertReqMsgBuilder: ...
def public_key_der(self, spki_der: bytes) -> CertReqMsgBuilder: ...
def popo_ra_verified(self) -> CertReqMsgBuilder: ...
def publication_action(self, action: int) -> CertReqMsgBuilder: ...
def add_pub_info(self, pub_method: int) -> CertReqMsgBuilder: ...
def pub_location_uri(self, pub_method: int, uri: str) -> CertReqMsgBuilder: ...
def pub_location_rfc822(self, pub_method: int, email: str) -> CertReqMsgBuilder: ...
def pub_location_dns(self, pub_method: int, host: str) -> CertReqMsgBuilder: ...
def pub_location_directory_name(self, pub_method: int, name_der: bytes) -> CertReqMsgBuilder: ...
def build(self) -> CertReqMsg: ...
# Raises ValueError if stored Name/SPKI bytes are invalid.
```
## CertReqMessagesBuilder
Fluent builder for a CRMF batch.
```python
class CertReqMessagesBuilder:
def __init__(self) -> None: ...
def add_request(self, req: CertReqMsg) -> CertReqMessagesBuilder: ...
def build(self) -> CertReqMessages: ...
```
## Publication method constants
| `PUB_METHOD_DONT_CARE` | 0 | No publication preference |
| `PUB_METHOD_X500` | 1 | Publish in X.500 directory |
| `PUB_METHOD_WEB` | 2 | Publish via HTTP/HTTPS URI |
| `PUB_METHOD_LDAP` | 3 | Publish in LDAP directory |
## OID constants
| `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 |
| `ID_REG_CTRL_PKI_ARCHIVE_OPTIONS` | PKI archive options control |
| `ID_REG_CTRL_OLD_CERT_ID` | Old certificate ID control |
| `ID_REG_CTRL_PROTOCOL_ENCR_KEY` | Protocol encryption key control |
| `ID_REG_INFO_UTF8_PAIRS` | UTF-8 pairs registration info |
| `ID_REG_INFO_CERT_REQ` | Certificate request registration info |
## Usage
```python
import synta.crmf as crmf
# Build a CRMF request
req = (
crmf.CertReqMsgBuilder()
.cert_req_id(1)
.subject_name(subject_name_der)
.public_key_der(spki_der)
.popo_ra_verified()
.build()
)
batch = crmf.CertReqMessagesBuilder().add_request(req).build()
batch_der = batch.to_der()
# Parse incoming CRMF
msgs = crmf.CertReqMessages.from_der(data)
for msg in msgs:
print(f"id={msg.cert_req_id}, popo={msg.popo_type}")
if msg.subject_der:
import synta
attrs = synta.parse_name_attrs(msg.subject_der)
print(f" subject: {attrs}")
```
See also [CMP Messages](cmp.md) for the CMP envelope that carries CRMF requests.