====== Scenario 2.3: Create Multi-SAN CSR ====== **Category:** [[.:start|Certificate Signing Requests (CSR)]] \\ **Complexity:** *** (Medium-High) \\ **Prerequisites:** Key pair available \\ **Estimated Time:** 10-15 minutes ---- ===== Description ===== This scenario describes creating a CSR with **multiple Subject Alternative Names (SANs)**. This is necessary for certificates that need to secure multiple domains, subdomains, or IP addresses. **Use cases:** * Multi-domain certificates (SAN certificates) * Wildcard + explicit domains combined * Internal + external names * Load balancer with multiple backends ---- ===== SAN Types ===== ^ Type ^ GeneralName Tag ^ Example ^ Usage ^ | DNS | dNSName (2) | www.example.com | Websites, APIs | | IP | iPAddress (7) | 192.168.1.100 | Internal services | | Email | rfc822Name (1) | admin@example.com | S/MIME | | URI | uniformResourceIdentifier (6) | https://example.com | SAML, OIDC | | UPN | otherName (0) | user@domain.local | Windows Auth | ---- ===== Code Example (C#) ===== using WvdS.Security.Cryptography.X509Certificates.Extensions.PQ; using var ctx = PqCryptoContext.Initialize(); using var key = ctx.GenerateKeyPair(PqAlgorithm.MlDsa65); var dn = new DnBuilder() .AddCN("example.com") // Primary domain .AddO("Example GmbH") .AddC("DE") .Build(); // Multi-SAN with different types var extensions = new ExtBuilder() .SubjectAlternativeName(new[] { // DNS names "dns:example.com", "dns:www.example.com", "dns:api.example.com", "dns:app.example.com", "dns:*.dev.example.com", // Wildcard for dev // IP addresses (for internal access) "ip:10.0.0.100", "ip:192.168.1.50", // IPv6 "ip:2001:db8::1" }) .KeyUsage(KeyUsageFlags.DigitalSignature | KeyUsageFlags.KeyEncipherment) .ExtendedKeyUsage(ExtKeyUsage.ServerAuth) .Build(); var csr = ctx.CreateCertificateRequest(key, dn, extensions); // Output all SANs Console.WriteLine("Subject Alternative Names:"); foreach (var san in csr.SubjectAlternativeNames) { Console.WriteLine($" - {san}"); } File.WriteAllText("multi-san.csr.pem", csr.ToPem()); ---- ===== Combining Wildcard + Explicit ===== var extensions = new ExtBuilder() .SubjectAlternativeName(new[] { "dns:example.com", // Root domain (wildcard does not cover this!) "dns:*.example.com", // All 1st level subdomains "dns:*.api.example.com", // API subdomains "dns:legacy.old-domain.com" // Alternative domain }) .Build(); **Important:** Wildcards (''*.example.com'') only cover one level and not the root domain itself! Therefore always specify both ''example.com'' AND ''*.example.com''. ---- ===== Kubernetes / Cloud-Native ===== var extensions = new ExtBuilder() .SubjectAlternativeName(new[] { // Kubernetes Service DNS "dns:my-service", "dns:my-service.default", "dns:my-service.default.svc", "dns:my-service.default.svc.cluster.local", // Headless Service (Pod DNS) "dns:*.my-service.default.svc.cluster.local", // External Ingress Domain "dns:api.example.com" }) .Build(); ---- ===== Limits and Best Practices ===== ^ Aspect ^ Recommendation ^ Reason ^ | Number of SANs | Max. 100 | Performance, certificate size | | Wildcard levels | Only 1 level | RFC 6125 restriction | | IP addresses | Only when necessary | IPs change more frequently | | Internal names | Separate certificates | Security separation | ---- ===== Related Scenarios ===== ^ Relationship ^ Scenario ^ Description ^ | **Next Step** | [[en:int:pqcrypt:szenarien:zertifikate:server_cert|3.1 Server Certificate]] | Sign CSR | | **Alternative** | [[en:int:pqcrypt:szenarien:zertifikate:wildcard_cert|3.5 Wildcard Certificate]] | Wildcard only | | **Foundation** | [[.:csr_server|2.1 Server CSR]] | Simple server CSR | ---- << [[.:csr_client|<- 2.2 Client CSR]] | [[.:start|^ CSR Overview]] | [[.:csr_verarbeiten|2.4 Process CSR ->]] >> {{tag>scenario csr san multi-domain wildcard}} ---- //Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional//