|
2 | 2 | using System.Collections.Concurrent; |
3 | 3 | using System.Collections.Generic; |
4 | 4 | using System.Diagnostics; |
| 5 | +using System.IO; |
5 | 6 | using System.Linq; |
6 | 7 | using System.Threading.Tasks; |
7 | | -using Certify.Models.Hub; |
8 | 8 | using Certify.Models; |
| 9 | +using Certify.Models.Config; |
| 10 | +using Certify.Models.Hub; |
9 | 11 | using Certify.Models.Providers; |
10 | 12 | using Certify.Models.Reporting; |
11 | 13 | using Certify.Models.Shared; |
12 | | -using Certify.Models.Config; |
| 14 | +using Certify.Shared.Core.Utils.PKI; |
13 | 15 |
|
14 | 16 | namespace Certify.Management |
15 | 17 | { |
@@ -531,6 +533,87 @@ public async Task<List<ActionStep>> GeneratePreview(ManagedCertificate item) |
531 | 533 | return await new PreviewManager().GeneratePreview(item, serverProvider, this, _credentialsManager); |
532 | 534 | } |
533 | 535 |
|
| 536 | + /// <summary> |
| 537 | + /// Prepare an export of a managed certificate in the given format (if certificate present) |
| 538 | + /// </summary> |
| 539 | + /// <param name="item"></param> |
| 540 | + /// <returns></returns> |
| 541 | + public async Task<ActionResult<byte[]>> ExportCertificate(string managedCertId, string format) |
| 542 | + { |
| 543 | + var item = await GetManagedCertificate(managedCertId); |
| 544 | + |
| 545 | + if (string.IsNullOrEmpty(item?.CertificatePath) || !File.Exists(item?.CertificatePath)) |
| 546 | + { |
| 547 | + return new ActionResult<byte[]>("Source certificate file is not present. Export cannot continue.", false); |
| 548 | + } |
| 549 | + |
| 550 | + if (string.IsNullOrWhiteSpace(format)) |
| 551 | + { |
| 552 | + format = "pfx"; |
| 553 | + } |
| 554 | + |
| 555 | + try |
| 556 | + { |
| 557 | + var pfxData = File.ReadAllBytes(item.CertificatePath); |
| 558 | + |
| 559 | + var certPwd = ""; |
| 560 | + |
| 561 | + // if credential used for private key, check if we can decrypt that (unless we exporting PFX which is just a file copy) |
| 562 | + if (!string.IsNullOrWhiteSpace(item.CertificatePasswordCredentialId) && format != "pfx") |
| 563 | + { |
| 564 | + var cred = await GetCredentialsManager().GetUnlockedCredentialsDictionary(item.CertificatePasswordCredentialId); |
| 565 | + if (cred != null) |
| 566 | + { |
| 567 | + certPwd = cred["password"]; |
| 568 | + } |
| 569 | + else |
| 570 | + { |
| 571 | + return new ActionResult<byte[]>($"Export - the credentials for this export could not be unlocked or were not accessible {item.CertificatePasswordCredentialId}.", false); |
| 572 | + } |
| 573 | + } |
| 574 | + |
| 575 | + byte[] result = []; |
| 576 | + |
| 577 | + if (format == "pfx") |
| 578 | + { |
| 579 | + result = pfxData; |
| 580 | + } |
| 581 | + else if (format == "pem_key") |
| 582 | + { |
| 583 | + result = CertUtils.GetCertComponentsAsPEMBytes(pfxData, certPwd, ExportFlags.PrivateKey); |
| 584 | + } |
| 585 | + else if (format == "pem_fullchain") |
| 586 | + { |
| 587 | + result = CertUtils.GetCertComponentsAsPEMBytes(pfxData, certPwd, ExportFlags.EndEntityCertificate | ExportFlags.IntermediateCertificates); |
| 588 | + } |
| 589 | + else if (format == "pem_fullchain_key") |
| 590 | + { |
| 591 | + result = CertUtils.GetCertComponentsAsPEMBytes(pfxData, certPwd, ExportFlags.PrivateKey | ExportFlags.EndEntityCertificate | ExportFlags.IntermediateCertificates); |
| 592 | + } |
| 593 | + else if (format == "pem_fullchain_root") |
| 594 | + { |
| 595 | + result = CertUtils.GetCertComponentsAsPEMBytes(pfxData, certPwd, ExportFlags.EndEntityCertificate | ExportFlags.IntermediateCertificates | ExportFlags.RootCertificate); |
| 596 | + } |
| 597 | + else if (format == "pem_fullchain_root_key") |
| 598 | + { |
| 599 | + result = CertUtils.GetCertComponentsAsPEMBytes(pfxData, certPwd, ExportFlags.PrivateKey | ExportFlags.EndEntityCertificate | ExportFlags.IntermediateCertificates | ExportFlags.RootCertificate); |
| 600 | + } |
| 601 | + |
| 602 | + if (result.Length == 0) |
| 603 | + { |
| 604 | + return new ActionResult<byte[]>($"Export - no files where selected for export or export could not be applied for source certificate.", false); |
| 605 | + } |
| 606 | + else |
| 607 | + { |
| 608 | + return new ActionResult<byte[]> { Result = result, IsSuccess = true }; |
| 609 | + } |
| 610 | + } |
| 611 | + catch (Exception exp) |
| 612 | + { |
| 613 | + return new ActionResult<byte[]>($"Export - {exp}", false); |
| 614 | + } |
| 615 | + } |
| 616 | + |
534 | 617 | public async Task<List<DnsZone>> GetDnsProviderZones(string providerTypeId, string credentialId) |
535 | 618 | { |
536 | 619 | var dnsHelper = new Core.Management.Challenges.DnsChallengeHelper(_credentialsManager); |
|
0 commit comments