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); }
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)); }
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)); }