Научно-образовательный IT-форум при КНИТУ-КАИ

Объявление

Семинар на тему «Восстановление кривых изменений вегетационных индексов по данным космической съемки (на примере индекса NDVI)» Д.А. Колесов (NextGIS). Дата и время: 24.11.2017 в 15.00; адрес: г.Казань, ул. Б.Красная, д.55, ауд. 428.

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » Научно-образовательный IT-форум при КНИТУ-КАИ » Задачи и вопросы » [+] Верификация сертификата X.509


[+] Верификация сертификата X.509

Сообщений 1 страница 10 из 25

1

ИСХОДНЫЕ ДАННЫЕ:
В материалах статьи http://habrahabr.ru/post/194664/ сказано, как сгенерировать самоподписанный сертификат. Приводится исходный код программы на C#:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.Security.Cryptography.X509Certificates;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.X509;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Crypto.Prng;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Math;

namespace generate
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            var KeyGenerate = new RsaKeyPairGenerator();
            KeyGenerate.Init(new KeyGenerationParameters(new SecureRandom(new CryptoApiRandomGenerator()), 1024));
            AsymmetricCipherKeyPair kp = KeyGenerate.GenerateKeyPair();
            var gen = new X509V3CertificateGenerator();
            var certName = new X509Name("CN=CA");
            var serialNo = new BigInteger("1", 10);
            gen.SetSerialNumber(serialNo);
            gen.SetSubjectDN(certName);
            gen.SetIssuerDN(certName);
            gen.SetNotAfter(DateTime.Now.AddYears(100));
            gen.SetNotBefore(DateTime.Now);
            gen.SetSignatureAlgorithm("SHA1WITHRSA");
            gen.SetPublicKey(kp.Public);
            var myCert = gen.Generate(kp.Private);
            byte[] result = DotNetUtilities.ToX509Certificate(myCert).Export(X509ContentType.Cert);
            FileStream fs = new FileStream(textBox1.Text+".crt", FileMode.Create);     
            fs.Write(result, 0, result.Length);
            fs.Flush();
            fs.Close();
            MessageBox.Show("Сертификат создан!");
        }
    }
}


ВОПРОС:
Как проверить, что сертификат верный? Привести код программы на С#, считывающий сгенерированный сертификат и проверяющий, что сертификат правильный.

http://forumfiles.ru/files/000c/4b/84/26892.jpg Решение

2

using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Windows.Forms;
using System.IdentityModel.Selectors;
using System.IdentityModel;

public class MyX509CertificateValidator : X509CertificateValidator
{
string allowedIssuerName;
public MyX509CertificateValidator(string allowedIssuerName)
{
if (allowedIssuerName == null)
{
throw new ArgumentNullException("allowedIssuerName");
}

this.allowedIssuerName = allowedIssuerName;
}
public override void Validate(X509Certificate certificate)
{
// Check that there is a certificate.
if (certificate == null)
{
throw new ArgumentNullException("certificate");
}

// Check that the certificate issuer matches the configured issuer

}
}

3

Кукарин Тимур гр 4306 написал(а):

using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Windows.Forms;
using System.IdentityModel.Selectors;
using System.IdentityModel;

public class MyX509CertificateValidator : X509CertificateValidator
...
}

А где здесь верификация (см. тему)? :)

4

Выводит данные сертификата на консоль, в т.ч. верификацию .
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;

namespace x509Verify
{
    class Program
    {
        static void Main(string[] args)
        {
            X509Store store = new X509Store("MY",StoreLocation.CurrentUser);
            store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);

            X509Certificate2Collection collection = (X509Certificate2Collection)store.Certificates;
            X509Certificate2Collection fcollection = (X509Certificate2Collection)collection.Find(X509FindType.FindByTimeValid,DateTime.Now,false);
            X509Certificate2Collection scollection = X509Certificate2UI.SelectFromCollection(fcollection, "Test Certificate Select","Select a certificate from the following list to get information on that certificate",X509SelectionFlag.MultiSelection);
            Console.WriteLine("Number of certificates: {0}{1}",scollection.Count,Environment.NewLine);
            X509Chain ch = new X509Chain();
           
        foreach (X509Certificate2 x509 in scollection)
        {
            try
            {
                ch.Build(x509);
                byte[] rawdata = x509.RawData;
                Console.WriteLine("Content Type: {0}{1}",X509Certificate2.GetCertContentType(rawdata),Environment.NewLine);
                Console.WriteLine("Friendly Name: {0}{1}",x509.FriendlyName,Environment.NewLine);
                Console.WriteLine("Certificate Verified?: {0}{1}",CertificateVerificationCallBack(x509,x509,ch, System.Net.Security.SslPolicyErrors.RemoteCertificateChainErrors),Environment.NewLine);
                X509Certificate2UI.DisplayCertificate(x509);
                x509.Reset();
            }
            catch (CryptographicException)
            {
                Console.WriteLine("Information could not be written out for this certificate.");
                Console.ReadKey();
            }
        }
        store.Close();
        ServicePointManager.ServerCertificateValidationCallback = CertificateVerificationCallBack;
       
        }

        private static bool CertificateVerificationCallBack(
         object sender,
         System.Security.Cryptography.X509Certificates.X509Certificate certificate,
         System.Security.Cryptography.X509Certificates.X509Chain chain,
         System.Net.Security.SslPolicyErrors sslPolicyErrors)
        {
            // If the certificate is a valid, signed certificate, return true.
            if (sslPolicyErrors == System.Net.Security.SslPolicyErrors.None)
            {
                return true;
            }

            // If there are errors in the certificate chain, look at each error to determine the cause.
            if ((sslPolicyErrors & System.Net.Security.SslPolicyErrors.RemoteCertificateChainErrors) != 0)
            {
                if (chain != null && chain.ChainStatus != null)
                {
                    foreach (System.Security.Cryptography.X509Certificates.X509ChainStatus status in chain.ChainStatus)
                    {
                        if ((certificate.Subject == certificate.Issuer) &&
                           (status.Status == System.Security.Cryptography.X509Certificates.X509ChainStatusFlags.UntrustedRoot))
                        {
                            continue;
                        }
                        else
                        {
                            if (status.Status != System.Security.Cryptography.X509Certificates.X509ChainStatusFlags.NoError)
                            {
                                return false;
                            }
                        }
                    }
                }

                return true;
            }
            else
            {
               return false;
            }
        }
    }
}

5

Диляра, хорошее указание, спасибо! Но не знаю, применимо ли это для самоподписывающего сертификата, как в нашем случае? :) Сомневаюсь что-то...

Запусти программу и сгенерируй сертификат, вот ссылка на проект:
https://www.dropbox.com/sh/uceg2uavbx5u … mZB0a?dl=0

Далее напиши вторую программу по верификации, проверь. Жду результатов! :)

6

using System;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.IO;
using System.Security.Cryptography.X509Certificates;

class CertSelect
{
static void Main()
{
X509Store store = new X509Store("MY", StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);

X509Certificate2Collection collection = (X509Certificate2Collection)store.Certificates;
X509Certificate2Collection fcollection = (X509Certificate2Collection)collection.Find(X509FindType.FindByTimeValid, DateTime.Now, false);
X509Certificate2Collection scollection = X509Certificate2UI.SelectFromCollection(fcollection, "Test Certificate Select", "Select a certificate from the following list to get information on that certificate", X509SelectionFlag.MultiSelection);
Console.WriteLine("Number of certificates: {0}{1}", scollection.Count, Environment.NewLine);

foreach (X509Certificate2 x509 in scollection)
{
try
{
byte[] rawdata = x509.RawData;
Console.WriteLine("Content Type: {0}{1}", X509Certificate2.GetCertContentType(rawdata), Environment.NewLine);
Console.WriteLine("Friendly Name: {0}{1}", x509.FriendlyName, Environment.NewLine);
Console.WriteLine("Certificate Verified?: {0}{1}", x509.Verify(), Environment.NewLine);
Console.WriteLine("Simple Name: {0}{1}", x509.GetNameInfo(X509NameType.SimpleName, true), Environment.NewLine);
Console.WriteLine("Signature Algorithm: {0}{1}", x509.SignatureAlgorithm.FriendlyName, Environment.NewLine);
Console.WriteLine("Private Key: {0}{1}", x509.PrivateKey.ToXmlString(false), Environment.NewLine);
Console.WriteLine("Public Key: {0}{1}", x509.PublicKey.Key.ToXmlString(false), Environment.NewLine);
Console.WriteLine("Certificate Archived?: {0}{1}", x509.Archived, Environment.NewLine);
Console.WriteLine("Length of Raw Data: {0}{1}", x509.RawData.Length, Environment.NewLine);
X509Certificate2UI.DisplayCertificate(x509);
x509.Reset();
}
catch (CryptographicException)
{
Console.WriteLine("Information could not be written out for this certificate.");
}
}
store.Close();
}
}

7

Тимур, не наблюдаю принципиальной разницы с предыдущим кодом Диляры, поэтому замечание то же.  :)

8

landwatersun
Поскольку сертификат самоподписанный, то нет возможности обратиться к третьему лицу и проверить его достоверность.
Его лишь можно считать, проверить хэш сумму и посмотреть что в нем записано (кем выдан, когда  и т.д.).

А вот сетрификат второго уровня можно проверить при наличии корневого сертификата, т.к. отпечаток корневого сертификата помещается в сетрификат второго уровня.

Код:
class Program
    {
        private static void Main(string[] args)
        {
            byte[] caBytes = File.ReadAllBytes(args[0]);
            byte[] certBytes = File.ReadAllBytes(args[1]);

            if (VerifyCertificate(caBytes, certBytes))
            {
                Console.WriteLine("Valid!");
            }
            else
            {
                Console.WriteLine("NOT valid!!!");
            }
        }

        static bool VerifyCertificate(byte[] primaryCertificate, byte[] additionalCertificates)
        {
            var certParser = new X509CertificateParser();
            
            var cert = certParser.ReadCertificate(additionalCertificates);
            var primaryCert = certParser.ReadCertificate(primaryCertificate);
        
            var id = new AuthorityKeyIdentifier(
                SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(primaryCert.GetPublicKey()),
                new GeneralNames(new GeneralName(primaryCert.SubjectDN)),
                primaryCert.SerialNumber);

            X509Extension ext = new X509Extension(false, new DerOctetString(id));
            byte[] checkBytes = ext.Value.GetEncoded();

            var data = cert.GetExtensionValue(X509Extensions.AuthorityKeyIdentifier.Id);
            byte[] certBytes = data.GetEncoded();

            return !checkBytes.Where((t, i) => t != certBytes[i]).Any();
        }

9

rozh написал(а):

...
А вот сертификат второго уровня можно проверить при наличии корневого сертификата, т.к. отпечаток корневого сертификата помещается в сертификат второго уровня.

Роман, полагаю, программный код, приведенный тобою, относился к проверке сертификата второго уровня? :)

10

Поскольку сертификат самоподписанный, то нет возможности обратиться к третьему лицу и проверить его достоверность.

Роман, согласен, проверить достоверность сертификата на базе третьего лица нельзя (самоподписанные сертификаты образуют специальный тип сертификатов УЦ, в которых издатель сертификата является одновременно субъектом сертификата).

В предложенном коде (см. первый пост) сгенерированный сертификат содержит открытый ключ и цифровую подпись, которая получена путем вычисления RSA_by_private_key(SHA1(TBS)), где TBS - определенная часть сертификата (см. http://habrahabr.ru/post/194664/). Судя по коду закрытый ключ, на базе которого была получена цифровая подпись, является парным открытому ключу.

gen.SetPublicKey(kp.Public);     
var myCert = gen.Generate(kp.Private);


Таким образом, проверить самодписанный сертификат можно так:
RSA_by_public_key(RSA_by_private_key(SHA1(TBS))) == SHA1(TBS).

Вот этот кусок программного кода и запрашиваю для получения "АВТОМАТА"? :)


Вы здесь » Научно-образовательный IT-форум при КНИТУ-КАИ » Задачи и вопросы » [+] Верификация сертификата X.509