AspNetCoreCertificates icon indicating copy to clipboard operation
AspNetCoreCertificates copied to clipboard

ImportExport password issues with on OSX

Open BillBaird opened this issue 4 years ago • 2 comments

I've been trying to get this working on OSX. A few issues are easily handled, such as OSX's lack of support for "FriendlyName". However, I've been unable to get the ImportExportTests to execute properly.

The ImportExportTests.ImportExportECPrivateKeyPublicKeyPairPem test fails on these lines:

            var roundTripFullCert =
                importExport.CreateCertificateWithPrivateKey(
                    roundTripPublicKeyPem, 
                    roundTripRsaPrivateKeyPem, "1234");

with the error

Interop+AppleCrypto+AppleCommonCryptoCryptographicException : MAC verification failed during PKCS12 import (wrong password?)
   at Interop.AppleCrypto.X509ImportCertificate(Byte[] bytes, X509ContentType contentType, SafePasswordHandle importPassword, SafeKeychainHandle keychain, Boolean exportable, SafeSecIdentityHandle& identityHandle)
   at Internal.Cryptography.Pal.AppleCertificatePal.FromBlob(Byte[] rawData, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags)
   at System.Security.Cryptography.X509Certificates.X509Certificate..ctor(Byte[] rawData, String password, X509KeyStorageFlags keyStorageFlags)
   at System.Security.Cryptography.X509Certificates.X509Certificate2..ctor(Byte[] rawData, String password)
   at CertificateManager.PemDecoder.CreateCertificateWithPrivateKey(X509Certificate2 certificate, AsymmetricAlgorithm privateKey, String password) in /Users/bill/ws/SB/Certificates/AspNetCoreCertificates/src/CertificateManager/PemDecoder.cs:line 152
   at CertificateManager.ImportExportCertificate.CreateCertificateWithPrivateKey(X509Certificate2 certificate, AsymmetricAlgorithm privateKey, String password) in /Users/bill/ws/SB/Certificates/AspNetCoreCertificates/src/CertificateManager/ImportExportCertificate.cs:line 193
   at CertificateManagerTests.ImportExportTests.ImportExportECPrivateKeyPublicKeyPairPem() in /Users/bill/ws/SB/Certificates/AspNetCoreCertificates/src/CertificateManagerTests/ImportExportTests.cs

Similar issues occur on the tests ImportExportRsaPrivateKeyPublicKeyPairPem and ImportExportSingleChainedECPrivateKeyPublicKeyPairPem, always on the call importExport.CreateCertificateWithPrivateKey.

Any chance of getting this library to work on OSX? This is the only real issue that I've run into with it.

BillBaird avatar May 02 '20 00:05 BillBaird

Hi @BillBaird thanks for your feedback. I would love to get this support this, get this to work on OSX, problem is, I have no idea about OSX. I will start looking into this, and build up my knowlegde, so this will work. If you make any progress, have have more pointers, PRs, I would be very grateful.

Greetings Damien

damienbod avatar May 03 '20 05:05 damienbod

Hello @damienbod. I have been pulling my hair out trying to get one implementation to work on Windows, OSX, and Linux and although I am not working on it directly, have had some insight. My focus has been on ECDsa keys and chain of trust creating a PFX file (PCKS#12).

Stumbling on your CreateCertificateWithPrivateKey in PemDecoder, I saw Pkcs12Builder for the first time. Indeed, it is new in .net core 3.0. I saw your comment on OpenSSL requiring a file to have a mac. From there, I noticed this little caveat at the end of the remarks section in https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.pkcs.pkcs12builder.sealwithmac?view=dotnet-plat-ext-3.1.

The hash algorithm used on a fresh installation of Windows 7 when exporting via X509Certificate.Export as a PKCS#12 PFX is SHA1 with an iteration count of 2000. Due to collision problems with SHA1, Microsoft recommends a security model based on SHA256 or better; however, some PFX readers may only support SHA1.

Since my goal was to create a PFX containing the full chain of trust, but only the private key from the leaf certificate, I used Pkcs12Builder and that comment to create the following Export routine:

/// <summary>
/// Exports one or more certificates in PKCS12 format representing a chain of trust.  The certificates should start with the leaf
/// node of the trust tree working their way up to the root CA.
///
/// Note that this implementation is for ECDsa keys.
/// </summary>
/// <param name="privateKeyPassword">A password used to shroud the private key of the leaf certificate</param>
/// <param name="pkcs12Password">A password using to seal the exported PKCS12 bytes</param>
/// <param name="cert">A set of one or more certificates with the leaf node (the one which for which the private key should be included) given first.</param>
public static byte[] ExportTrustChainWithPrivateKey(string privateKeyPassword, string pkcs12Password, params X509Certificate2[] cert)
{
    var builder = new Pkcs12Builder();
    var contents = new Pkcs12SafeContents();
    for (int i = 0; i < cert.Length; i++)
    {
        contents.AddCertificate(cert[i]);
        if (i == 0)
            contents.AddShroudedKey(cert[i].GetECDsaPrivateKey(), privateKeyPassword, new PbeParameters(PbeEncryptionAlgorithm.TripleDes3KeyPkcs12, HashAlgorithmName.SHA1, 2000));
    }
    builder.AddSafeContentsUnencrypted(contents);

    // OpenSSL requires the file to have a mac, without mac this will run on Windows but not on Linux
    // See hash algorithm comment at the end of
    // https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.pkcs.pkcs12builder.sealwithmac?view=dotnet-plat-ext-3.1
    // SHA1 is used since using SHA2565 here does not work on OSX.
    builder.SealWithMac(pkcs12Password, HashAlgorithmName.SHA1, 2000);
    return builder.Encode();
}

This is all new to me, so I don't know if what I've done here is "correct", but it works identically on Windows, OSX, and Linux (and I'll soon be trying to use these in Xamarin), which was my goal.

I can't commit to any PRs right now, but if I can carve out some time I'll try to get to them. I'm thankful that Pkcs12Builder exists (along with a whole new set of related classes), but I feel like we're pioneers in that there are no examples, etc. out there and MS's docs are not real useful (the one little caveat in the remarks was the most useful thing I found).

Thanks for your library. I never would have made it this far without it. Bill

BillBaird avatar May 06 '20 19:05 BillBaird