Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/keyfactor-bootstrap-workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ jobs:
uses: keyfactor/actions/.github/workflows/starter.yml@v2
secrets:
token: ${{ secrets.V2BUILDTOKEN}}
APPROVE_README_PUSH: ${{ secrets.APPROVE_README_PUSH}}
APPROVE_README_PUSH: ${{ secrets.V2BUILDTOKEN }}
gpg_key: ${{ secrets.KF_GPG_PRIVATE_KEY }}
gpg_pass: ${{ secrets.KF_GPG_PASSPHRASE }}
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,6 @@
# 1.2.3
* Fix for JSON serialization for revocation
# 1.2.4
* Fix for null reference exception on sync with 0 records
* Fix for null reference exception on sync with 0 records
# 1.2.5
* Allow for manually specifying lifetime length for enrollment
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ REQUIRED. This flag lets Keyfactor know if the certificate can contain multiple
OPTIONAL. If the organization name is provided as a parameter here, the Sectigo gateway will use that organization name in requests, instead of the O field in the subject.
* ```Department```
OPTIONAL. If your Sectigo account is using department-level products, put the appropriate department name here. Previous versions of the Sectigo gateway read this value from the OU field of the subject, which is now deprecated.
* ```Lifetime```
OPTIONAL. The term length (in days) to use for enrollment. If not provided, the default is the first value available in the profile definition in your Sectigo account.

```json
"Templates": {
Expand All @@ -114,7 +116,8 @@ OPTIONAL. If your Sectigo account is using department-level products, put the ap
"Parameters": {
"MultiDomain": "false",
"Organization": "Organization Name",
"Department": "Department Name"
"Department": "Department Name",
"Lifetime": "199"
}
}
}
Expand Down
5 changes: 4 additions & 1 deletion readme_source.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ REQUIRED. This flag lets Keyfactor know if the certificate can contain multiple
OPTIONAL. If the organization name is provided as a parameter here, the Sectigo gateway will use that organization name in requests, instead of the O field in the subject.
* ```Department```
OPTIONAL. If your Sectigo account is using department-level products, put the appropriate department name here. Previous versions of the Sectigo gateway read this value from the OU field of the subject, which is now deprecated.
* ```Lifetime```
OPTIONAL. The term length (in days) to use for enrollment. If not provided, the default is the first value available in the profile definition in your Sectigo account.

```json
"Templates": {
Expand All @@ -72,7 +74,8 @@ OPTIONAL. If your Sectigo account is using department-level products, put the ap
"Parameters": {
"MultiDomain": "false",
"Organization": "Organization Name",
"Department": "Department Name"
"Department": "Department Name",
"Lifetime": "199"
}
}
}
Expand Down
37 changes: 30 additions & 7 deletions src/SectigoCAProxy/SectigoCAProxy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ public override void Synchronize(ICertificateDataReader certificateDataReader,
throw producerTask.Exception.Flatten();
}

Logger.Trace($"SYNC TRACE ({certToAdd.Id}): Processing record {certToAdd.Id}");
CAConnectorCertificate dbCert = null;
//serial number is blank on certs that have not been issued (awaiting approval)
if (!String.IsNullOrEmpty(certToAdd.SerialNumber))
Expand Down Expand Up @@ -127,7 +128,7 @@ public override void Synchronize(ICertificateDataReader certificateDataReader,
else
{
//No certificate in the DB by SN. Need to download to get full certdata required for sync process
Logger.Trace($"Attempt to Pickup Certificate {certToAdd.CommonName} (ID: {certToAdd.Id})");
Logger.Trace($"SYNC TRACE ({certToAdd.Id}): Attempt to Pickup Certificate {certToAdd.CommonName}");
var certdataApi = Task.Run(async () => await Client.PickupCertificate(certToAdd.Id, certToAdd.CommonName)).Result;
if (certdataApi != null)
certData = Convert.ToBase64String(certdataApi.GetRawCertData());
Expand All @@ -138,12 +139,14 @@ public override void Synchronize(ICertificateDataReader certificateDataReader,
Logger.Debug($"Certificate Data unavailable for {certToAdd.CommonName} (ID: {certToAdd.Id}). Skipping ");
continue;
}
Logger.Trace($"SYNC TRACE ({certToAdd.Id}): Retrieved cert data: {certData}");
string prodId = "";
try
{
Logger.Trace($"Cert ID: {certToAdd.Id.ToString()}");
Logger.Trace($"Sync ID: {syncReqId.ToString()}");
Logger.Trace($"Product ID: {certToAdd.CertType.id.ToString()}");
Logger.Trace($"SYNC TRACE ({certToAdd.Id}): Cert ID: {certToAdd.Id.ToString()}");
Logger.Trace($"SYNC TRACE ({certToAdd.Id}): Sync ID: {syncReqId.ToString()}");
Logger.Trace($"SYNC TRACE ({certToAdd.Id}): Product ID: {certToAdd.CertType.id.ToString()}");
Logger.Trace($"SYNC TRACE ({certToAdd.Id}): Status: {certToAdd.status}");
prodId = certToAdd.CertType.id.ToString();
}
catch { }
Expand Down Expand Up @@ -392,6 +395,26 @@ public override EnrollmentResult Enroll(ICertificateDataReader certificateDataRe
Logger.Trace($"Found {enrollmentProfile.name} profile for enroll request");
}

int termLength;
var profileTerms = Task.Run(async () => await GetProfileTerms(int.Parse(productInfo.ProductID))).Result;
if (productInfo.ProductParameters.ContainsKey("Lifetime") && !string.IsNullOrEmpty(productInfo.ProductParameters["Lifetime"]))
{
var tempTerm = int.Parse(productInfo.ProductParameters["Lifetime"]);
if (profileTerms.Contains(tempTerm))
{
termLength = tempTerm;
}
else
{
Logger.Error($"Specified term length of {tempTerm} does not match available terms for product ID {productInfo.ProductID}. Available terms are {string.Join(",", profileTerms)}");
throw new Exception($"Specified term length of {tempTerm} does not match available terms for product ID {productInfo.ProductID}");
}
}
else
{
termLength = profileTerms[0];
}

int sslId;
string priorSn = string.Empty;
Certificate newCert = null;
Expand All @@ -410,7 +433,7 @@ public override EnrollmentResult Enroll(ICertificateDataReader certificateDataRe
{
csr = csr,
orgId = requestOrgId,
term = Task.Run(async () => await GetProfileTerm(int.Parse(productInfo.ProductID))).Result,
term = termLength,
certType = enrollmentProfile.id,
//External requestor is expected to be an email. Use config to pull the enrollment field or send blank
//sectigo will default to the account (API account) making the request.
Expand Down Expand Up @@ -642,10 +665,10 @@ private async Task<Organization> GetOrganizationAsync(string orgName)
return orgList.Organizations.Where(x => x.name.ToLower().Equals(orgName.ToLower())).FirstOrDefault();
}

private async Task<int> GetProfileTerm(int profileId)
private async Task<List<int>> GetProfileTerms(int profileId)
{
var profileList = await Client.ListSslProfiles();
return profileList.SslProfiles.Where(x => x.id == profileId).FirstOrDefault().terms[0];
return profileList.SslProfiles.Where(x => x.id == profileId).FirstOrDefault().terms.ToList();
}

private async Task<Profile> GetProfile(int profileId)
Expand Down
Loading