public void ReadOctetString()
        {
            byte[] data =
            {
                0x04, 0x42, 0x00, 0x43, 0x3E, 0x10, 0x5C, 0xE3, 0x75, 0x42, 0x54, 0x37, 0xDD, 0x3C, 0x35,
                0x2D, 0x2F, 0x32, 0x69, 0x09, 0x3C, 0x73, 0x23, 0x1C, 0x6F, 0x2A, 0xE6, 0x12, 0xE5, 0x78, 0x20,
                0xC8, 0xF3, 0x46, 0xA8, 0x19, 0xCB, 0xD8, 0x60, 0x02, 0xAA, 0x81, 0x79, 0x77, 0x1A, 0x86, 0x7E,
                0xE2, 0x45, 0x53, 0x66, 0xDF, 0x9A, 0xC2, 0x3C, 0x77, 0xCD, 0x12, 0x6B, 0x8D, 0x74, 0x83, 0x2B,
                0x8A, 0xEA, 0x24, 0xAA, 0xD7,
            };

            byte[] expected =
            {
                0x00, 0x43, 0x3E, 0x10, 0x5C, 0xE3, 0x75, 0x42, 0x54, 0x37, 0xDD, 0x3C, 0x35,
                0x2D, 0x2F, 0x32, 0x69, 0x09, 0x3C, 0x73, 0x23, 0x1C, 0x6F, 0x2A, 0xE6, 0x12, 0xE5, 0x78, 0x20,
                0xC8, 0xF3, 0x46, 0xA8, 0x19, 0xCB, 0xD8, 0x60, 0x02, 0xAA, 0x81, 0x79, 0x77, 0x1A, 0x86, 0x7E,
                0xE2, 0x45, 0x53, 0x66, 0xDF, 0x9A, 0xC2, 0x3C, 0x77, 0xCD, 0x12, 0x6B, 0x8D, 0x74, 0x83, 0x2B,
                0x8A, 0xEA, 0x24, 0xAA, 0xD7,
            };

            int offset = 0;

            byte[] actual = LightweightPkcs8Decoder.ReadOctetString(data, ref offset);

            Assert.AreEqual(expected, actual);
        }
        public void VerifyECDecoderWithRSAKey()
        {
            byte[] data = Convert.FromBase64String(RsaPrivateKey);

            Exception ex = Assert.Throws <InvalidDataException>(() => LightweightPkcs8Decoder.DecodeECDsaPkcs8(data, null));

            Assert.AreEqual("Invalid PKCS#8 Data", ex.Message);
        }
        public void VerifyRsaDecoderWithEcKey()
        {
            byte[] data = Convert.FromBase64String(EcSecp256k1PrivateKey);

            Exception ex = Assert.Throws <InvalidDataException>(() => LightweightPkcs8Decoder.DecodeRSAPkcs8(data));

            Assert.AreEqual("Invalid PKCS#8 Data", ex.Message);
        }
        public void ReadBitString(byte[] data)
        {
            int offset = 0;

            byte[] actual = LightweightPkcs8Decoder.ReadBitString(data, ref offset);

            Assert.AreEqual(new byte[] { 0x11, 0x22, 0x33, 0x00 }, actual);
        }
        public void ReadObjectIdentifier(string expectedOid, byte[] data)
        {
            int offset = 0;

            string actualOid = LightweightPkcs8Decoder.ReadObjectIdentifier(data, ref offset);

            Assert.AreEqual(expectedOid, actualOid);
        }
        public void ReadUnsupportedObjectIdentifier()
        {
            byte[] data   = new byte[] { 0x06, 0x06, 0x2B, 0x88, 0x80, 0x80, 0x80, 0x00 }; // 1.3.2147483648
            int    offset = 0;

            Exception ex = Assert.Throws <InvalidDataException>(() => LightweightPkcs8Decoder.ReadObjectIdentifier(data, ref offset));

            Assert.AreEqual("Unsupported PKCS#8 Data", ex.Message);
        }
        public void ReadInvalidObjectIdentifier()
        {
            byte[] data   = new byte[] { 0x06, 0x03, 0x2B, 0x80, 0x01 };
            int    offset = 0;

            Exception ex = Assert.Throws <InvalidDataException>(() => LightweightPkcs8Decoder.ReadObjectIdentifier(data, ref offset));

            Assert.AreEqual("Invalid PKCS#8 Data", ex.Message);
        }
        public void ReadInvalidBitString()
        {
            byte[] data   = { 0x30, 0x01, 0x08 };
            int    offset = 0;

            Exception ex = Assert.Throws <InvalidDataException>(() => LightweightPkcs8Decoder.ReadBitString(data, ref offset));

            Assert.AreEqual("Invalid PKCS#8 Data", ex.Message);
        }
        public void ReadTooLongOctsetString()
        {
            byte[] data   = { 0x04, 0x83, 0x01, 0x00, 0x00, 0xff, 0xff, /* ... */ };
            int    offset = 0;

            Exception ex = Assert.Throws <InvalidDataException>(() => LightweightPkcs8Decoder.ReadOctetString(data, ref offset));

            Assert.AreEqual("Invalid PKCS#8 Data", ex.Message);
        }
        public void ECDecoderPrime256v1RequiresPublicKey()
        {
#if NET461
            Assert.Ignore("ECC is not supported before .NET Framework 4.7");
#endif
            byte[] data = Convert.FromBase64String(EcPrime256v1PrivateKeyImported);

            Exception ex = Assert.Throws <InvalidDataException>(() => LightweightPkcs8Decoder.DecodeECDsaPkcs8(data, null));
            Assert.AreEqual("Unsupported PKCS#8 Data", ex.Message);
        }
        public void VerifyDecoder()
        {
            byte[] data = Convert.FromBase64String(PrivateKey);

            using RSA fromPem = LightweightPkcs8Decoder.DecodeRSAPkcs8(data);
            using RSA fromPfx = (RSA) new X509Certificate2(Convert.FromBase64String(Pfx)).PrivateKey;

            RSAParameters pemParams = fromPem.ExportParameters(false);
            RSAParameters pfxParams = fromPfx.ExportParameters(false);

            Assert.AreEqual(pfxParams.Modulus, pemParams.Modulus);
            Assert.AreEqual(pfxParams.Exponent, pemParams.Exponent);
        }
示例#12
0
        public void VerifyDecoder()
        {
            byte[] data = ExtractPrivateKeyBlobFromPem(File.ReadAllText(Path.Combine(TestContext.CurrentContext.TestDirectory, "Data", "cert.pem")));

            RSA fromPem = LightweightPkcs8Decoder.DecodeRSAPkcs8(data);
            RSA fromPfx = (RSA) new X509Certificate2(Path.Combine(TestContext.CurrentContext.TestDirectory, "Data", "cert.pfx"), "password").PrivateKey;

            RSAParameters pemParams = fromPem.ExportParameters(false);
            RSAParameters pfxParams = fromPfx.ExportParameters(false);

            Assert.AreEqual(pfxParams.Modulus, pemParams.Modulus);
            Assert.AreEqual(pfxParams.Exponent, pemParams.Exponent);
        }
        // Not using TestCaseSource because params too long for friendly test case rendering.
        private static void VerifyECDecoder(string key, CertificateKeyCurveName keyCurveName, string signature, string cer = null)
        {
#if NET461
            Assert.Ignore("ECC is not supported before .NET Framework 4.7");
#endif
            byte[] data           = Convert.FromBase64String(key);
            byte[] signatureBytes = Convert.FromBase64String(signature);

            ECDsa publicKey = null;
            try
            {
                if (cer != null)
                {
                    byte[] publicKeyData = Convert.FromBase64String(cer);
                    using X509Certificate2 certificate = new X509Certificate2(publicKeyData);

                    publicKey = certificate.GetECDsaPublicKey();
                }

                using ECDsa keyPair = LightweightPkcs8Decoder.DecodeECDsaPkcs8(data, publicKey);

                Assert.AreEqual(keyCurveName.GetKeySize(), keyPair.KeySize);
                Assert.IsTrue(keyPair.VerifyData(Encoding.UTF8.GetBytes("test"), signatureBytes, HashAlgorithmName.SHA256));
            }
            catch (Exception ex) when(
                (ex is CryptographicException || (ex is TargetInvocationException && ex.InnerException is CryptographicException)) &&
                RuntimeInformation.IsOSPlatform(OSPlatform.OSX) &&
                keyCurveName == CertificateKeyCurveName.P256 || keyCurveName == CertificateKeyCurveName.P256K)
            {
                Assert.Ignore("The curve is not supported by the current platform");
            }
            finally
            {
                publicKey?.Dispose();
            }
        }
            private async ValueTask <X509Certificate2> LoadCertificateFromPemFileAsync(bool async, string clientCertificatePath, CancellationToken cancellationToken)
            {
                if (!(Certificate is null))
                {
                    return(Certificate);
                }

                string certficateText;

                try
                {
                    if (!async)
                    {
                        certficateText = File.ReadAllText(clientCertificatePath);
                    }
                    else
                    {
                        cancellationToken.ThrowIfCancellationRequested();

                        using (StreamReader sr = new StreamReader(clientCertificatePath))
                        {
                            certficateText = await sr.ReadToEndAsync().ConfigureAwait(false);
                        }
                    }

                    Regex certificateRegex = new Regex("(-+BEGIN CERTIFICATE-+)(\n\r?|\r\n?)([A-Za-z0-9+/\n\r]+=*)(\n\r?|\r\n?)(-+END CERTIFICATE-+)", RegexOptions.CultureInvariant, TimeSpan.FromSeconds(5));
                    Regex privateKeyRegex  = new Regex("(-+BEGIN PRIVATE KEY-+)(\n\r?|\r\n?)([A-Za-z0-9+/\n\r]+=*)(\n\r?|\r\n?)(-+END PRIVATE KEY-+)", RegexOptions.CultureInvariant, TimeSpan.FromSeconds(5));

                    Match certificateMatch = certificateRegex.Match(certficateText);
                    Match privateKeyMatch  = privateKeyRegex.Match(certficateText);

                    if (!certificateMatch.Success)
                    {
                        throw new InvalidDataException("Could not find certificate in PEM file");
                    }

                    if (!privateKeyMatch.Success)
                    {
                        throw new InvalidDataException("Could not find private key in PEM file");
                    }

                    // ImportPkcs8PrivateKey was added in .NET Core 3.0, it is only present on Core.  If we can't find this method, we have a lightweight decoder we can use.
                    MethodInfo importPkcs8PrivateKeyMethodInfo = typeof(RSA).GetMethod("ImportPkcs8PrivateKey", BindingFlags.Instance | BindingFlags.Public, null, new Type[] { typeof(ReadOnlySpan <byte>), typeof(int).MakeByRefType() }, null);

                    // CopyWithPrivateKey is present in .NET Core 2.0+ and .NET 4.7.2+.
                    MethodInfo copyWithPrivateKeyMethodInfo = typeof(RSACertificateExtensions).GetMethod("CopyWithPrivateKey", BindingFlags.Static | BindingFlags.Public, null, new Type[] { typeof(X509Certificate2), typeof(RSA) }, null);

                    if (copyWithPrivateKeyMethodInfo == null)
                    {
                        throw new PlatformNotSupportedException("The current platform does not support reading a private key from a PEM file");
                    }

                    RSA privateKey;

                    if (importPkcs8PrivateKeyMethodInfo != null)
                    {
                        privateKey = RSA.Create();

                        // Because ImportPkcs8PrivateKey takes a ReadOnlySpan<byte> as an argument, we can not call it directly via MethodInfo.Invoke (since all the arguments to the function
                        // have to be passed to MethodInfo.Invoke in an object array, and you can't put a byref type like ReadOnlySpan<T> in an array. So we create a delegate with the
                        // correct signature bound to the privateKey we want to import into and invoke that.
                        ImportPkcs8PrivateKeyDelegate importPrivateKey = (ImportPkcs8PrivateKeyDelegate)importPkcs8PrivateKeyMethodInfo.CreateDelegate(typeof(ImportPkcs8PrivateKeyDelegate), privateKey);
                        importPrivateKey(Convert.FromBase64String(privateKeyMatch.Groups[3].Value), out int _);
                    }
                    else
                    {
                        privateKey = LightweightPkcs8Decoder.DecodeRSAPkcs8(Convert.FromBase64String(privateKeyMatch.Groups[3].Value));
                    }

                    X509Certificate2 certWithoutPrivateKey = new X509Certificate2(Convert.FromBase64String(certificateMatch.Groups[3].Value));
                    Certificate = (X509Certificate2)copyWithPrivateKeyMethodInfo.Invoke(null, new object[] { certWithoutPrivateKey, privateKey });

                    // On desktop NetFX it appears the PrivateKey property is not initialized after calling CopyWithPrivateKey
                    // this leads to an issue when using the MSAL ConfidentialClient which uses the PrivateKey property to get the
                    // signing key vs. the extension method GetRsaPrivateKey which we were previously using when signing the claim ourselves.
                    // Because of this we need to set PrivateKey to the instance we created to deserialize the private key
                    if (Certificate.PrivateKey == null)
                    {
                        Certificate.PrivateKey = privateKey;
                    }

                    return(Certificate);
                }
                catch (Exception e) when(!(e is OperationCanceledException))
                {
                    throw new CredentialUnavailableException("Could not load certificate file", e);
                }
            }
 public void GetECDsaPrivateKeyImportedOid()
 {
     // cspell:ignore Secp
     byte[] data = Convert.FromBase64String(EcSecp256k1PrivateKey);
     Assert.AreEqual("1.2.840.10045.2.1", LightweightPkcs8Decoder.DecodePrivateKeyOid(data));
 }
 public void GetRSAPrivateKeyOid()
 {
     byte[] data = Convert.FromBase64String(PrivateKey);
     Assert.AreEqual("1.2.840.113549.1.1.1", LightweightPkcs8Decoder.DecodePrivateKeyOid(data));
 }
示例#17
0
        public void VerifyDecoderBadData()
        {
            byte[] data = ExtractPrivateKeyBlobFromPem(File.ReadAllText(Path.Combine(TestContext.CurrentContext.TestDirectory, "Data", "cert-invalid.pem")));

            Assert.Throws <InvalidDataException>(() => LightweightPkcs8Decoder.DecodeRSAPkcs8(data));
        }
        public void VerifyDecoderBadData()
        {
            byte[] data = Convert.FromBase64String(InvalidPrivateKey);

            Assert.Throws <InvalidDataException>(() => LightweightPkcs8Decoder.DecodeRSAPkcs8(data));
        }