# Task: Emissão de certificado SSL/TLS

I want my application to do what Lacuna's "Emissão de certificado SSL/TLS" demo does: Emita um certificado SSL/TLS para um site com o Amplia.

- Docs: https://docs.lacunasoftware.com/pt-br/articles/amplia
- Live demo: https://try.lacunasoftware.com/pt/amplia/issue-ssl-tls-certificate
- This demo for AI agents: https://try.lacunasoftware.com/pt/amplia/issue-ssl-tls-certificate.md

## Samples

Lacuna lists no sample for this task: rely on the docs and the call sequence below.

## Call sequence

Recorded on 2026-10-12 against the real products with Lacuna's public test certificates and data. Keys, tokens, sessions, ids, file contents and personal data are masked.

### 1. PKI SDK makes an RSA 2048 key and a CSR for the first DNS name on the server before the order, so a key failure costs no Amplia order.

On the server, in process: `RSA.Create(2048), then CsrGenerator.GenerateCsr(key, dnsName)`

### 2. Amplia creates the SSL order with the DNS names, the subject and the key usages set explicitly, then issues the certificate from the CSR with key media PC.

On the server: `IAmpliaService.CreateOrderAsync, then IAmpliaService.IssueCertificateAsync(orderId, csr, KeyMedia.PC)`

`POST https://amplia.lacunasoftware.com/api/orders/ssl` → 200

Request:

```json
{
  "Parameters": {
    "Format": 2,
    "DnsNames": [
      "www.example.com"
    ],
    "SubjectName": {
      "Organization": "Lacuna Software Demo",
      "CommonName": "www.example.com",
      "OrganizationalUnits": [
        "Lab"
      ]
    },
    "KeyUsages": [
      3,
      7
    ],
    "ExtendedKeyUsages": [
      1
    ]
  },
  "CAId": "00000000-0000-0000-0000-000000000000",
  "Kind": 1,
  "Validity": "90.00:00:00",
  "IssuePendingApproval": false
}
```

Response:

```json
{
  "parameters": {
    "format": "Ssl",
    "dnsNames": [
      "www.example.com"
    ],
    "subjectName": {
      "organization": "Lacuna Software Demo",
      "commonName": "www.example.com",
      "organizationalUnits": [
        "Lab"
      ]
    },
    "keyUsages": [
      "DigitalSignature",
      "KeyEncipherment"
    ],
    "extendedKeyUsages": [
      "ServerAuth"
    ]
  },
  "canDelete": true,
  "canEdit": true,
  "id": "00000000-0000-0000-0000-000000000000",
  "subscriptionId": "00000000-0000-0000-0000-000000000000",
  "dateCreated": "2026-10-12T02:08:02.241402+00:00",
  "caId": "00000000-0000-0000-0000-000000000000",
  "name": "www.example.com",
  "alias": "www.example.com",
  "status": "Pending",
  "kind": "PublicKey",
  "format": "Ssl",
  "issuePendingApproval": false
}
```

`POST https://amplia.lacunasoftware.com/api/v2/certificates` → 200

Request:

```json
{
  "OrderId": "00000000-0000-0000-0000-000000000000",
  "Csr": "<Csr, 914 bytes>",
  "KeyMedia": 1
}
```

Response:

```json
{
  "parameters": {
    "format": "Ssl",
    "dnsNames": [
      "www.example.com"
    ],
    "subjectName": {
      "organization": "Lacuna Software Demo",
      "organizationUnit": "Lab",
      "commonName": "www.example.com",
      "allValues": {
        "2.5.4.10": [
          "Lacuna Software Demo"
        ],
        "2.5.4.11": [
          "Lab"
        ],
        "2.5.4.3": [
          "www.example.com"
        ]
      },
      "organizationalUnits": [
        "Lab"
      ],
      "dnString": "CN=www.example.com,OU=Lab,O=Lacuna Software Demo"
    },
    "keyUsages": [
      "DigitalSignature",
      "KeyEncipherment"
    ],
    "extendedKeyUsages": [
      "ServerAuth"
    ]
  },
  "info": {
    "subjectName": {
      "organization": "Lacuna Software Demo",
      "organizationUnit": "Lab",
      "commonName": "www.example.com",
      "allValues": {
        "2.5.4.10": [
          "Lacuna Software Demo"
        ],
        "2.5.4.11": [
          "Lab"
        ],
        "2.5.4.3": [
          "www.example.com"
        ]
      },
      "organizationalUnits": [
        "Lab"
      ],
      "dnString": "CN=www.example.com,OU=Lab,O=Lacuna Software Demo"
    },
    "issuerName": {
      "country": "BR",
      "organization": "Lacuna Software",
      "organizationUnit": "IT",
      "commonName": "Lacuna CA Test v7",
      "allValues": {
        "2.5.4.6": [
          "BR"
        ],
        "2.5.4.10": [
          "Lacuna Software"
        ],
        "2.5.4.11": [
          "IT"
        ],
        "2.5.4.3": [
          "Lacuna CA Test v7"
        ]
      },
      "organizationalUnits": [
        "IT"
      ],
      "dnString": "CN=Lacuna CA Test v7,OU=IT,O=Lacuna Software,C=BR"
    },
    "serialNumber": "<hex, 19 bytes>",
    "validityStart": "2026-10-12T02:03:02+00:00",
    "validityEnd": "2027-01-10T02:08:02+00:00",
    "crlDistributionPoints": [
      "http://ca.lacunasoftware.com/crls/lacuna-ca-test-v7.crl",
      "http://ca.lacunasoftware.com.br/crls/lacuna-ca-test-v7.crl"
    ],
    "ocspUris": [],
    "isSelfSigned": false,
    "isCA": false
  },
  "content": "<content, 1485 bytes>",
  "hasSignedAgreement": false,
  "id": "00000000-0000-0000-0000-000000000000",
  "subscriptionId": "00000000-0000-0000-0000-000000000000",
  "caId": "00000000-0000-0000-0000-000000000000",
  "dateIssued": "2026-10-12T02:08:02.4310809+00:00",
  "dateEffective": "2026-10-12T02:03:02+00:00",
  "dateExpires": "2027-01-10T02:08:02+00:00",
  "alias": "www.example.com",
  "subjectDisplayName": "www.example.com",
  "serialNumber": "<hex, 19 bytes>",
  "isCA": false,
  "kind": "PublicKey",
  "format": "Ssl",
  "isPendingApproval": false
}
```

### 3. The key is exported as PKCS#8 PEM for the .key file, and PKI SDK puts it and the certificate in a PKCS#12 with no password for the .pfx, kept in memory for the downloads.

On the server, in process: `RSA.ExportPkcs8PrivateKeyPem(), then Pkcs12Generator.Generate(key, certificate, alias, password)`

## Patterns to copy

- The DNS names and subject come from the order's `SslCertificateParameters`, never from the CSR: set the DNS names, the subject, the key usages (DigitalSignature, KeyEncipherment) and the extended key usage (ServerAuth) explicitly, on your CA.
- Check a user's CSR locally before calling Amplia: at most 16 KB, PEM, Base64 or DER, an RSA key of 2048 to 4096 bits or an EC key on P-256 or P-384, and a signature that verifies. Send Amplia the request re-encoded as PEM.
- Check DNS names locally too (1 to 10, lowercased, `*` only as the whole leftmost label, no IP addresses), and map Amplia's `BadDnsName` and `BadCsr` codes to messages of your own.
- What you hand back depends on who made the key: with a server key, a .pfx, the PEM private key and a .crt with the leaf and its issuing CA, never the root; with the user's CSR, only the .crt. Keep keys in memory only.

## What to do

Implement this in my project with its existing stack, language, framework and conventions, following the call sequence and the patterns above, and adapting the samples rather than copying them whole. Ask me before adding any dependency or package. Keep API keys and private keys out of the browser and out of the repository.
