Привет, Хабр! Представляю вашему вниманию перевод заключительной статьи "Java Certificate" автора Jakob Jenkov из серии статей для начинающих, желающих освоить основы криптографии в Java.


Оглавление:


  1. Java Cryptography
  2. Java Cipher
  3. MessageDigest
  4. Mac
  5. Signature
  6. KeyPair
  7. KeyGenerator
  8. KeyPairGenerator
  9. KeyStore
  10. Keytool
  11. Certificate
  12. CertificateFactory
  13. CertPath

Java Certificate (Сертификат)


Класс сертификата (java.security.cert.Certificate) представляет собой сертификат удостоверяющий принадлежность некоторому субъекту, например, пользователю. Экземпляр класса сертификата содержит имя и другие сведения об объекте, который он идентифицирует, а также, возможно, цифровую подпись от центра сертификации (ЦС). Класс Certificate является абстрактным классом, поэтому, вы можете использовать в качестве типа переменной Certificate, а ваша переменная всегда будет указывать на подкласс. Этот класс имеет один подкласс — X509Certificate, который представляет сертификат X.509, использующийся в качестве сертификата в протоколах HTTPS и TLS.


Получение экземпляра сертификата


Вы можете получить экземпляр сертификата следующими способами:



Посмотрите эти два руководства для получения дополнительной информации о получении экземпляра сертификата.


getEncoded()


Метод getEncoded() сертификата возвращает закодированную версию сертификата в виде байтового массива. Например, если сертификат является сертификатом X509, возвращенный байтовый массив будет содержать версию экземпляра сертификата в кодировке X.590 (ASN.1 DER). Вот пример использования методаgetEncoded():


byte[] encodedCertificate = certificate.getEncoded();

getPublicKey()


Метод сертификата getPublicKey() возвращает открытый ключ этого экземпляра сертификата. Вот пример метода getPublicKey():


PublicKey certificatePublicKey = certificate.getPublicKey();

getType()


Метод getType() возвращает тип экземпляра сертификата. Пример getType():


String certificateType = certificate.getType();

verify()


Класс сертификата содержит три метода verify(). Эти методы могут использоваться для проверки того, что сертификат действительно подписан с закрытым ключом, соответствующим ожидаемому открытому ключу. Вот пример проверки сертификата:


// получение ожидаемого открытого ключа (не из сертификата!)
PublicKey expectedPublicKey = ... ;

try{
    certificate.verify(expectedPublicKey);

} catch (InvalidKeyException e) {
    // сертификат не был подписан данным открытым ключом

} catch (NoSuchAlgorithmException |
         NoSuchProviderException |
         SignatureException |
         CertificateException e){
    // что-то еще пошло не так
}

Метод verify() не возвращает значения. Если проверка не пройдена, будет выдано исключение InvalidKeyException. Если не сгенерировано исключение, экземпляр сертификата можно считать проверенным.


Java CertificateFactory (Фабрика сертификатов


Класс CertificateFactory (java.security.cert.CertificateFactory) способен создавать экземпляры сертификата (Certificate) из двоичных данных сертификатов с кодировками X.509 (ASN.1 DER). CertificateFactory также может создавать экземпляры CertPath. CertPath — это цепочка сертификатов, где каждый сертификат подписан следующим сертификатом в данной цепочке.


Создание экземпляра CertificateFactory


Прежде чем вы сможете создавать экземпляры Certificate, вы должны создать экземпляр CertificateFactory. Пример:


CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");

В этом примере создается экземпляр CertificateFactory, способный создавать экземпляры сертификата X.509 (X509Certificate — подкласс Certificate).


Создание экземпляра Certificate


Создав экземпляр CertificateFactory, вы можете начать создавать экземпляры Certificate. Это делается с помощью вызова метода generateCertificate(). Пример вызова методаgenerateCertificate():


InputStream certificateInputStream = new FileInputStream("my-x509-certificate.crt");

Certificate certificate = certificateFactory.generateCertificate(certificateInputStream);

Создание экземпляра CertPath


CertificateFactory также может создавать экземпляр CertPath. Экземпляр CertPath создается вызовом метода generateCertPath():


InputStream certificateInputStream = new FileInputStream("my-x509-certificate-chain.crt");

CertPath certPath = certificateFactory.generateCertPath(certificateInputStream);

Java CertPath (Цепочка сертификатов)


Класс CertPath (java.security.cert.CertPath) представляет цепочку сертификатов (объекты Certificate), где каждый сертификат является цифровым подписывающим лицом следующего сертификата в цепочке. Класс CertPath обычно используется для проверки сертификата личности вместе с сертификатами центров сертификации (ЦС), которые подписали сертификат.


Получение экземпляра CertPath


Обычно экземпляр CertPath получают из фабрики сертификатов (CertificateFactory или CertPathBuilder).


getCertificates()


Получив экземпляр CertPath, вы можете получить экземпляры Certificate, из которых состоит CertPath, вызвав метод getCertificates(). Вот пример получения сертификатов из экземпляра CertPath:


List<Certificate> certificates = certPath.getCertificates();

getType()


Метод getType() возвращает строку, указывающую, какой тип сертификатов (например, X.509) содержится в этом экземпляре CertPath. Вот пример получения типа CertPath через методом getType():


String type = certPath.getType();

Комментарии (9)


  1. maslyaev
    05.04.2019 18:39

    Мой вопрос покажется совсем чайниковским, но, уверяю, это не так.

    … представляет собой сертификат удостоверяющий принадлежность некоторому субъекту, например, пользователю.
    Принадлежность чего? Не может же ведь быть «просто принадлежность». Одну сторону отношения «принадлежит» мы обозначили (это у нас пользователь), но что у нас на другой стороне?


    1. Mingun
      05.04.2019 18:54

      Принадлежность приватного ключа, публичная часть которого в сертификате


      1. man41k Автор
        05.04.2019 18:58

        насколько мне известно сертификаты предназначены в основном для хранения открытых ключей. закрытые ключи в сертификатах редкая и не безопасная опция.


        1. Mingun
          05.04.2019 20:22

          А я разве сказал, что в сертификате закрытый ключ? В сертификате находится открытый ключ, из какого-то источника вы знаете, что он принадлежит Пете. Так как открытому ключу соответствует закрытый, то, подтвердив, что ключ действительно Петин, вы также транзитивно подтверждаете, что приватный ключ из пары открытый-закрытый ключ принадлежит Пете. А значит, шифруя открытым ключом сообщение или проверяя им подпись, вы можете быть уверены, что прочитает его/сгенерировал ее именно Петя, а ни кто иной.


          1. man41k Автор
            05.04.2019 21:10

            да, скорочтение не мой конек. прочитал совсем не то что написано((


    1. man41k Автор
      05.04.2019 18:55

      Вторая сторона — открытый ключ.


      1. maslyaev
        05.04.2019 23:55

        Который является частью… ну да, сертификата.
        Странно получается. По сути, файл с расширением «cer» — это публичный ключ. Этот ключ дополнен подписью удостоверяющего центра, которая подтверждает, что бинарные данные ключа соответствуют описательным полям (субъект, мэйл, то-сё). Но самая мякотка, суть и смысл существования этого файла — всё же ключ. Всё остальное, в том числе подпись УЦ — это дополнительные данные разной степени полезности.

        Почему же ключ не назвать ключом? Почему мы стабильно запрягаем телегу впереди лошади? Почему допускаем понятийную путаницу?

        Когда генерится ключевая пара, мы имеем два ключа — секретный и публичный. Публичный мы можем снабдить сертификатом соответствия. А можем и не снабжать. Можем снабдить, но оформить отдельным файликом. Почему бы и нет? Заливка ключа и сертификата к нему в один файл — это всего лишь один из возможных вариантов. В том же Биткоине, например, асимметричная криптография используется вовсю, но никаких сертификаций там отродясь нет.


  1. kovserg
    06.04.2019 00:46
    +1

    Тема не раскрыта.
    Хочется увидеть пример кода как сформировать сертификат (добавить туда атрибуты и дополнительные поля) и подписать другим сертификатом (к которому есть доверие).
    Как проверить валидность сертификата, не отозван ли он.


    1. Mingun
      06.04.2019 13:17

      Да. Первая статья вселяла хоть какую-то надежду, но уже с 3-й стало ясно, что тут просто сокращенно пересказывают javadoc.