Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/fix cert issue #4783

Draft
wants to merge 4 commits into
base: dev
Choose a base branch
from
Draft
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
40 changes: 35 additions & 5 deletions src/Commands/AzureAD/RegisterAzureADApp.cs
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
using PnP.Framework;
using PnP.PowerShell.Commands.Base;
using PnP.PowerShell.Commands.Enums;
using PnP.PowerShell.Commands.Model;
using PnP.PowerShell.Commands.Utilities;
using PnP.PowerShell.Commands.Utilities.REST;
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.IO;
using System.Linq;
using System.Management.Automation;
using System.Net.Http;
using System.Reflection;
using System.Security;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Threading.Tasks;
using TextCopy;
using OperatingSystem = PnP.PowerShell.Commands.Utilities.OperatingSystem;
using Resources = PnP.PowerShell.Commands.Properties.Resources;
using PnP.PowerShell.Commands.Base;
using System.Dynamic;
using PnP.PowerShell.Commands.Enums;
using TextCopy;

namespace PnP.PowerShell.Commands.AzureAD
{
@@ -486,7 +487,10 @@ private X509Certificate2 GetCertificate(PSObject record)
}
DateTime validFrom = DateTime.Today;
DateTime validTo = validFrom.AddYears(ValidYears);
cert = CertificateHelper.CreateSelfSignedCertificate(CommonName, Country, State, Locality, Organization, OrganizationUnit, CertificatePassword, CommonName, validFrom, validTo, Array.Empty<string>());

var psVersion = GetPSVersion();

cert = CertificateHelper.CreateSelfSignedCertificate(CommonName, Country, State, Locality, Organization, OrganizationUnit, CertificatePassword, CommonName, validFrom, validTo, Array.Empty<string>(), psVersion);

if (Directory.Exists(OutPath))
{
@@ -757,5 +761,31 @@ private void SetLogo(AzureADApp azureApp, string token)
WriteWarning("Logo File does not exist, ignoring setting the logo");
}
}

private string GetPSVersion()
{
var caller = AppDomain.CurrentDomain.GetAssemblies().SingleOrDefault(a => a.GetName().Name == "System.Management.Automation");
//var caller = Assembly.GetCallingAssembly();
var psVersionType = caller.GetType("System.Management.Automation.PSVersionInfo");
if (null != psVersionType)
{
PropertyInfo propInfo = psVersionType.GetProperty("PSVersion");
if (null == propInfo)
{
propInfo = psVersionType.GetProperty("PSVersion", BindingFlags.NonPublic | BindingFlags.Static);
}
var getter = propInfo.GetGetMethod(true);
var version = getter.Invoke(null, new object[] { });

if (null != version)
{
var versionType = version.GetType();
var versionProperty = versionType.GetProperty("Major");
var minorVersionProperty = versionType.GetProperty("Minor");
return ((int)versionProperty.GetValue(version)).ToString() + "." + ((int)minorVersionProperty.GetValue(version)).ToString();
}
}
return "";
}
}
}
2 changes: 2 additions & 0 deletions src/Commands/PnP.PowerShell.csproj
Original file line number Diff line number Diff line change
@@ -67,6 +67,8 @@

<PackageReference Include="Microsoft.Identity.Client.Extensions.Msal" Version="4.69.1" />

<PackageReference Include="Microsoft.Bcl.Cryptography" Version="9.0.2" />

<ProjectReference Include="..\ALC\PnP.PowerShell.ALC.csproj" />

</ItemGroup>
34 changes: 21 additions & 13 deletions src/Commands/Utilities/CertificateHelper.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
using System;
using PnP.Framework.Diagnostics;
using System;
using System.Collections.Generic;
using System.IO;
using System.Management.Automation;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using SecureString = System.Security.SecureString;
using System.Management.Automation;
using PnP.Framework.Diagnostics;

namespace PnP.PowerShell.Commands.Utilities
{
@@ -18,12 +18,12 @@ internal static string PrivateKeyToBase64(X509Certificate2 certificate, bool use
RSAParameters param = new RSAParameters();

var a = certificate.GetRSAPrivateKey();
using(var rsa = MakeExportable(a))

using (var rsa = MakeExportable(a))
{
param = rsa.ExportParameters(true);
}

string base64String;
using (var stream = new MemoryStream())
{
@@ -126,15 +126,15 @@ internal static X509Certificate2 GetCertificateFromStore(string thumbprint)
/// <returns>X509Certificate2 instance</returns>
/// <exception cref="PSArgumentException">Thrown if the certificate cannot be read</exception>
/// <exception cref="FileNotFoundException">Thrown if the certificate cannot be found at the provided path</exception>
internal static X509Certificate2 GetCertificateFromPath(Cmdlet cmdlet, string certificatePath, SecureString certificatePassword,
X509KeyStorageFlags x509KeyStorageFlags =
internal static X509Certificate2 GetCertificateFromPath(Cmdlet cmdlet, string certificatePath, SecureString certificatePassword,
X509KeyStorageFlags x509KeyStorageFlags =
X509KeyStorageFlags.Exportable |
X509KeyStorageFlags.MachineKeySet |
X509KeyStorageFlags.PersistKeySet)
{
if (System.IO.File.Exists(certificatePath))
{
Log.Debug("CertificateHelper",$"Reading certificate from file '{certificatePath}'");
Log.Debug("CertificateHelper", $"Reading certificate from file '{certificatePath}'");

var certFile = System.IO.File.OpenRead(certificatePath);
if (certFile.Length == 0)
@@ -145,7 +145,7 @@ internal static X509Certificate2 GetCertificateFromPath(Cmdlet cmdlet, string ce
var certificateBytes = new byte[certFile.Length];
certFile.Read(certificateBytes, 0, (int)certFile.Length);

Log.Debug("CertificateHelper",$"Opening certificate in file '{certificatePath}' {(certificatePassword == null ? "without" : "using")} a certificate password");
Log.Debug("CertificateHelper", $"Opening certificate in file '{certificatePath}' {(certificatePassword == null ? "without" : "using")} a certificate password");
try
{
var certificate = new X509Certificate2(
@@ -239,7 +239,7 @@ private static IEnumerable<string> SplitText(string text, int length)

#endregion

internal static X509Certificate2 CreateSelfSignedCertificate(string commonName, string country, string state, string locality, string organization, string organizationUnit, SecureString password, string friendlyName, DateTimeOffset from, DateTimeOffset to, string[] sanNames = null)
internal static X509Certificate2 CreateSelfSignedCertificate(string commonName, string country, string state, string locality, string organization, string organizationUnit, SecureString password, string friendlyName, DateTimeOffset from, DateTimeOffset to, string[] sanNames = null, string psVersion = "7.4")
{
SubjectAlternativeNameBuilder sanBuilder = new SubjectAlternativeNameBuilder();
if (sanNames != null)
@@ -268,8 +268,9 @@ internal static X509Certificate2 CreateSelfSignedCertificate(string commonName,
X500DistinguishedName distinguishedName = new X500DistinguishedName(distinguishedNameString);

#pragma warning disable CA1416 // Validate platform compatibility
using (RSA rsa = Platform.IsWindows ? MakeExportable(new RSACng(2048)) : RSA.Create(2048))
{
using (RSA rsa = RSA.Create(2048))
{
rsa.ExportRSAPrivateKey();
var request = new CertificateRequest(distinguishedName, rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);

request.CertificateExtensions.Add(
@@ -288,6 +289,13 @@ internal static X509Certificate2 CreateSelfSignedCertificate(string commonName,
certificate.FriendlyName = friendlyName;
}

string passString = password != null ? CredentialManager.SecureStringToString(password) : null;

if (psVersion == "7.5")
{
return X509CertificateLoader.LoadPkcs12(certificate.Export(X509ContentType.Pfx, password), passString, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet);
}

return new X509Certificate2(certificate.Export(X509ContentType.Pfx, password), password, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet);
}
#pragma warning restore CA1416 // Validate platform compatibility
14 changes: 7 additions & 7 deletions src/Commands/Utilities/CredentialManager.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
using System;
using Microsoft.Identity.Client.Extensions.Msal;
using Microsoft.Win32.SafeHandles;
using PnP.Framework.Modernization.Cache;
using System;
using System.Linq;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
@@ -7,9 +10,6 @@
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
using Microsoft.Identity.Client.Extensions.Msal;
using Microsoft.Win32.SafeHandles;
using PnP.Framework.Modernization.Cache;
using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME;

[assembly: InternalsVisibleTo("PnP.PowerShell.Tests")]
@@ -498,7 +498,7 @@ private static PSCredential ReadMacOSKeyChainEntry(string applicationName)
}
return null;
}
private static void WriteMacOSKeyChainEntry(string applicationName,string password)
private static void WriteMacOSKeyChainEntry(string applicationName, string password)
{
var keychain = new MacOSKeychain();
keychain.AddOrUpdate(applicationName, applicationName, password.ToByteArray());
@@ -507,14 +507,14 @@ private static void WriteMacOSKeyChainEntry(string applicationName,string passwo
private static bool DeleteMacOSKeyChainEntry(string name)
{
var keychain = new MacOSKeychain();
return keychain.Remove(name,name);
return keychain.Remove(name, name);
// var cmd = $"/usr/bin/security delete-generic-password -s '{name}'";
// var output = Shell.Bash(cmd);
// var success = output.Count > 1 && !output[0].StartsWith("security:");
// return success;
}

private static string SecureStringToString(SecureString value)
public static string SecureStringToString(SecureString value)
{
IntPtr valuePtr = IntPtr.Zero;
try