diff --git a/DigiCertSymCaProxy/Client/Models/San.cs b/DigiCertSymCaProxy/Client/Models/San.cs index 55575d8..37b014c 100644 --- a/DigiCertSymCaProxy/Client/Models/San.cs +++ b/DigiCertSymCaProxy/Client/Models/San.cs @@ -22,6 +22,6 @@ public class San : ISan [JsonProperty("other_name", NullValueHandling = NullValueHandling.Ignore)] public List OtherName { get; set; } [JsonProperty("registered_id", NullValueHandling = NullValueHandling.Ignore)] public List RegisteredId { get; set; } [JsonProperty("rfc822_name", NullValueHandling = NullValueHandling.Ignore)] public List Rfc822Name { get; set; } - [JsonProperty("user_principal_name", NullValueHandling = NullValueHandling.Ignore)] public List UserPrincipalName { get; set; } + [JsonProperty("user_principal_name", NullValueHandling = NullValueHandling.Ignore)] public List UserPrincipalName { get; set; } } } diff --git a/DigiCertSymCaProxy/RequestManager.cs b/DigiCertSymCaProxy/RequestManager.cs index c8db8a4..dd16d2b 100644 --- a/DigiCertSymCaProxy/RequestManager.cs +++ b/DigiCertSymCaProxy/RequestManager.cs @@ -1,13 +1,13 @@ -// Copyright 2023 Keyfactor -// Licensed under the Apache License, Version 2.0 (the "License"); you may -// not use this file except in compliance with the License. You may obtain a -// copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless -// required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES -// OR CONDITIONS OF ANY KIND, either express or implied. See the License for -// thespecific language governing permissions and limitations under the -// License. -using System; +// Copyright 2023 Keyfactor +// Licensed under the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. You may obtain a +// copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless +// required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES +// OR CONDITIONS OF ANY KIND, either express or implied. See the License for +// thespecific language governing permissions and limitations under the +// License. +using System; using System.Collections.Generic; using System.IO; using System.Reflection; @@ -23,6 +23,7 @@ using Org.BouncyCastle.Asn1.Pkcs; using Org.BouncyCastle.OpenSsl; using Org.BouncyCastle.Pkcs; +using System.Linq; namespace Keyfactor.AnyGateway.DigiCertSym { @@ -232,6 +233,49 @@ public SearchCertificateRequestType GetSearchCertificatesRequest(int pageCounter } } + private (Dictionary DNSOut, Dictionary MultiOut) ProcessSansArray( + string[] sanArray, string commonName) + { + Dictionary dnsOut = new Dictionary(); + Dictionary multiOut = new Dictionary(); + + if (sanArray.Length == 1) + { + var singleItem = sanArray.First(); + if (singleItem == commonName || string.IsNullOrWhiteSpace(commonName)) + { + dnsOut.Add(singleItem, singleItem); + } + else + { + throw new InvalidOperationException("Error: Single item does not match CommonName."); + } + } + else if (sanArray.Length > 1) + { + if (!string.IsNullOrWhiteSpace(commonName)) + { + if (!sanArray.Contains(commonName)) + { + throw new InvalidOperationException("Error: Multiple items, none of them match CommonName."); + } + else + { + dnsOut.Add(commonName, commonName); + multiOut = sanArray.Where(item => item != commonName) + .ToDictionary(item => item, item => item); + } + } + else + { + dnsOut.Add(sanArray.First(), sanArray.First()); + multiOut = sanArray.Skip(1).ToDictionary(item => item, item => item); + } + } + + return (dnsOut, multiOut); + } + public EnrollmentRequest GetEnrollmentRequest(EnrollmentProductInfo productInfo, string csr, Dictionary san) { @@ -303,38 +347,46 @@ public EnrollmentRequest GetEnrollmentRequest(EnrollmentProductInfo productInfo, Logger.Trace($"Enrollment Serialized JSON before DNS and OU, result: {JsonConvert.SerializeObject(enrollmentRequest)}"); - //5. Loop through DNS Entries, if coming from Cert bot, then need to get common name from here as well + Dictionary MultiOut=null; + + List dnsList = new List(); + + //5. If it contains the dns and it is not multi domain get the DNS if (san.ContainsKey("dns")) { - var dnsList = new List(); var dnsKp = san["dns"]; Logger.Trace($"dnsKP: {dnsKp}"); - var commonNameList = new List(); - var j = 1; - foreach (var item in dnsKp) + (Dictionary DNSOut, Dictionary MultiOut) result; + + if (!getCommonNameFromSubject) { - commonNameList.Add(item); - if (j < 2) - { - DnsName dns = new DnsName { Id = DnsConstantName, Value = item }; - dnsList.Add(dns); - } - else - { - DnsName dns = new DnsName { Id = DnsConstantName + j, Value = item }; - dnsList.Add(dns); - } - j++; + //Cert Bot flow, Cert Bot has no common name and the dns comes from the SAN blank for common name returns first DNS + result = ProcessSansArray(dnsKp, ""); } - string commonName = string.Join(",", commonNameList); + else + { + result = ProcessSansArray(dnsKp, enrollmentRequest?.Attributes?.CommonName); + } + + DnsName up = new DnsName { Id = DnsConstantName, Value = result.DNSOut.FirstOrDefault().Value }; + MultiOut = result.MultiOut; var jsonResultDns = JsonConvert.SerializeObject(enrollmentRequest); if (!getCommonNameFromSubject) - jsonResultDns = ReplaceCsrEntry(new[] { "CN", commonName }, jsonResult); + jsonResultDns = ReplaceCsrEntry(new[] { "CN", result.DNSOut.FirstOrDefault().Value }, jsonResult); enrollmentRequest = JsonConvert.DeserializeObject(jsonResultDns); + dnsList.Add(up); + + //5. Handle the multiple domain scenario domains go in a different attribute + if (MultiOut?.Count > 0) + { + DnsName mdns = new DnsName { Id = "custom_encode_dnsName_multi", Value = string.Join(",", MultiOut.Values) }; + dnsList.Add(mdns); + } + sn.DnsName = dnsList; } @@ -346,47 +398,23 @@ public EnrollmentRequest GetEnrollmentRequest(EnrollmentProductInfo productInfo, Logger.Trace($"upn: {upKp}"); - var k = 1; - foreach (var item in upKp) - { - if (k < 2) - { - UserPrincipalName up = new UserPrincipalName { Id = UpnConstantName, Value = item }; - upList.Add(up); - } - else - { - UserPrincipalName up = new UserPrincipalName { Id = UpnConstantName + k, Value = item }; - upList.Add(up); - } - k++; - } + //Multiple UPNs not supported by Digicert so take the first one in the list + UserPrincipalName up = new UserPrincipalName { Id = UpnConstantName, Value = upKp.FirstOrDefault() }; + upList.Add(up); sn.UserPrincipalName = upList; } //7. Loop through IP Entries - if (san.ContainsKey("ip4") || san.ContainsKey("ip6")) + if (san.ContainsKey("ipaddress")) { var ipList = new List(); - var ipKp = san.ContainsKey("ip4") ? san["ip4"] : san["ip6"]; + var ipKp = san["ipaddress"]; Logger.Trace($"ip: {ipKp}"); - var k = 1; - foreach (var item in ipKp) - { - if (k < 2) - { - IpAddress ip = new IpAddress { Id = IpConstantName, Value = item }; - ipList.Add(ip); - } - else - { - IpAddress ip = new IpAddress { Id = IpConstantName + k, Value = item }; - ipList.Add(ip); - } - k++; - } + //Multiple IP Addresses not supported by Digicert so take the first one in the list + IpAddress ip = new IpAddress { Id = IpConstantName, Value = ipKp.FirstOrDefault() }; + ipList.Add(ip); sn.IpAddress = ipList; } @@ -398,21 +426,9 @@ public EnrollmentRequest GetEnrollmentRequest(EnrollmentProductInfo productInfo, Logger.Trace($"mail: {mailKp}"); - var k = 1; - foreach (var item in mailKp) - { - if (k < 2) - { - Rfc822Name mail = new Rfc822Name { Id = EmailConstantName, Value = item }; - mailList.Add(mail); - } - else - { - Rfc822Name mail = new Rfc822Name { Id = EmailConstantName + k, Value = item }; - mailList.Add(mail); - } - k++; - } + //Multiple IP Addresses not supported by Digicert so take the first one in the list + Rfc822Name mail = new Rfc822Name { Id = EmailConstantName, Value = mailKp.FirstOrDefault() }; + mailList.Add(mail); sn.Rfc822Name = mailList; } @@ -425,11 +441,11 @@ public EnrollmentRequest GetEnrollmentRequest(EnrollmentProductInfo productInfo, var i = OuStartPoint; foreach (var ou in organizationalUnits) { - var organizationUnit = new OrganizationUnit { Id = OuStartPoint==0?"cert_org_unit":"cert_org_unit" + i, Value = ou }; + var organizationUnit = new OrganizationUnit { Id = OuStartPoint == 0 ? "cert_org_unit" : "cert_org_unit" + i, Value = ou }; orgUnits.Add(organizationUnit); i++; } - + var attributes = enrollmentRequest.Attributes; attributes.OrganizationUnit = orgUnits; attributes.San = sn;