Java за цифрово подписване на документи в уеб


Глава 1.Цифрови подписи и сертификати в Java



страница6/14
Дата14.08.2018
Размер2.83 Mb.
#78668
1   2   3   4   5   6   7   8   9   ...   14

Глава 1.Цифрови подписи и сертификати в Java


При реализацията на Java приложения, които работят с цифрови подписи, сертификати и смарт карти, се използват специфични Java библиотеки. Тези библиотеки ще са ни необходими при реализацията на нашата система за подписване на документи в уеб среда и затова сега ще ги разгледаме в детайли.

1.1.Java Cryptography Architecture и Java Cryptography Extension


За целите на подписването на документи, проверката на цифрови подписи и управлението на цифрови сертификати в Java платформата се използва Java Cryptography Architecture (JCA)
. JCA представлява спецификация, коя­то предоставя на програмистите достъп някои до криптографски услуги, работа с цифрови подписи и сертификати [JCA, 2004].

Наред с JCA за извършване на някои криптографски операции, като шиф­риране, дешифриране и генериране на ключове и др., се използва Java Cryptography Extension (JCE). JCE предоставя общ framework за импле­мен­тация и употреба на криптиращи алгоритми в Java [JCE, 2004].

От архитектурна гледна точка JCA и JCE са така проектирани, че да позволяват използването на различни имплементации на различни услуги от различни софтуерни доставчици. При работата с JCA и JCE програмистът избира имената на доставчиците на криптографски услуги (providers) и имената на алго­ритмите, които иска да използва. Различните доставчици на криптографски услуги реализират различно множество от крипто­графски услуги и алгоритми, които са достъпни по име.

Спецификациите JCA и JCE установяват стандарти за различните типове криптографски услуги и специфицират начините на използване на крипто­графските алгоритми. Реализацията на самите алгоритми е оставена на софтуерните доставчици.

В Java 2 платформата стандартно са реализирани голям брой крипто­графски алгоритми и услуги, но JCA и JCE и позволяват добавяне и на допълнителни собствени имплементации.

1.1.1.Основни класове за работа с цифрови подписи и сертификати


Архитектурата JCA предоставя класове и интерфейси за работа с публични и лични ключове, цифрови сертификати, подписване на съобщения, про­верка на цифрови подписи и достъп до защитени хранилища за ключове и сертификати. Стандартната имплементация на JCA и JCE предоставя средства за работа с X.509 сертификати и сертификационни вериги, подписване с различни алгоритми (RSA, DSA, ECDSA и др.), достъп до PKCS#12 хранилища, алгоритми за проверка на цифрови подписи (напр. PKIX) и достъп до смарт карти (в Java 1.5 и по-високите версии).

Най-важните класове и интерфейси за работа с цифрови подписи и сертификати се намират в пакетите java.security и java.security.cert. Ще дадем кратко описание на най-важните от тях, които са свързани с импле­ментацията на нашата система за цифрово подписване на документи в уеб среда.


java.security.PublicKey


Интерфейсът java.security.PublicKey представлява публичен ключ. Той може да бъде извлечен от даден цифров сертификат и да се използва при проверката на цифрови подписи.

java.security.PrivateKey


Интерфейсът java.security.PrivateKey представлява личен ключ. Той може да бъде извлечен от защитено хранилище (KeyStore) и да се използва за създаване на цифров подпис.

PrivateKey инстанциите реално могат и да не съдържат ключа, а само да предоставят интерфейс за достъп до него. Например ако даден личен ключ е записан върху смарт карта, той не може да бъде извлечен от нея, но може да бъде използван за подписване или криптиране посредством този интерфейс.

java.security.cert.Certificate


Абстрактният клас java.security.cert.Certificate е базов за всички класове, които представляват цифрови сертификати. Съдържа в себе си публичен ключ и информация за лицето, което е негов собственик, както и информация за издателя на сертификата. За представяне на всеки конкре­тен тип сертификати (например X.509, PGP и т. н.) се използва съответен наследник на този клас.

java.security.cert.X509Certificate


Класът java.security.cert.X509Certificate представлява X.509 v.3 сер­тификат. Той предлага методи за достъп до отделните му атрибути – собственик (Subject), издател (Issuer), публичен ключ на собственика, срок на валидност, версия, сериен номер, алгоритъм, използван за цифровата сигнатура, цифрова сигнатура, допълнителни разширения и др. Данните за един X509Certificate са достъпни само за четене.

Стандартно е реализиран и метод verify(), който проверява дали серти­фикатът е подписан от даден публичен ключ. Тази възможност може да се използва за проверка дали даден сертификат е подписан от даден друг сертификат (т. е. дали вторият е издател на първия).


java.security.KeyStore


Класът java.security.KeyStore се използва за достъп до защитени хра­нилища за ключове и сертификати. Той предоставя методи за зареждане на хранилище от поток или от смарт карта, записване на хранилище в поток, преглед на записаната в хранилището информация, извличане на ключове, сертифи­кати и сертификационни вериги, промяна на записаната в храни­лището информация и др.

Поддържат се няколко формата на хранилища – PFX (съгласно PKCS#12 стандарта), JKS (Java Key Store) и смарт карта (по стандарта PKCS#11). При създаване на обект от класа KeyStore форматът на хранилището се задава от параметър. Възможни стойности в JDK 1.5 са “JKS”, “PKCS12” и “PKCS11”.

Обектите, записани в едно хранилище, са достъпни по име (alias), а личните ключове са достъпни по име и парола. Под едно и също име (alias) в дадено хранилище може да има записани едновременно както серти­фикат, така и сертифика­ционна верига и личен ключ.

Ето един пример за зареждане на хранилище от файл и отпечатване на всички сертификати, записани в него:



KeyStore keyStore = KeyStore.getInstance("PKCS12");

FileInputStream stream = new FileInputStream("example.pfx");



try {

String keyStorePassword = "**********";

keyStore.load(stream, keyStorePassword.toCharArray());

} finally {

stream.close();

}

Enumeration aliasesEnum = keyStore.aliases();



while (aliasesEnum.hasMoreElements()) {

String alias = (String)aliasesEnum.nextElement();

System.out.println("Alias: " + alias);

X509Certificate cert = (X509Certificate) keyStore.getCertificate(alias);

System.out.println("Certificate: " + cert);

}

java.security.Signature


Класът java.security.Signature предоставя функционалност за подпис­ване на документи и проверка на цифрови подписи (сигнатури).

При създаването на инстанция на класа Signature се задава име на алгоритъм за цифрови подписи, който да бъде използван. Името на алгоритъма се образува от името на алгоритъма за хеширане и името на алгоритъма за подписване (криптиране) на хеш-стойността. Поддържат се различни алгоритми като SHA1withRSA, SHA1withDSA, MD5withRSA и др.


Полагане на цифров подпис с Java


За подписване на съобщения се използва класът Signature. Използват се методите му initSign(), на който се подава личен ключ, update(), на който се подава съобщението, което трябва да се подпише, и sign(), който подписва съобщението и връща изчислената сигнатура.

Ето примерен код за подписване на дадено съобщение с даден личен ключ:



public static byte[] signDocument(byte[] aDocument, PrivateKey aPrivateKey)

throws GeneralSecurityException {

Signature signatureAlgorithm = Signature.getInstance("SHA1withRSA");

signatureAlgorithm.initSign(aPrivateKey);

signatureAlgorithm.update(aDocument);



byte[] signature = signatureAlgorithm.sign();

return signature;

}

Верификация на цифров подпис с Java


За верификация на цифров подпис се използва отново класът Signature. Използват се методите му initVerify(), на който се подава публичния ключ, който да бъде използван, update(), на който се подава подписаното съобщение, и verify(), на който се подава сигнатурата, която ще се проверява. В резултат verify() връща булева стойност – дали верифика­цията на сигнатурата е успешна.

Ето примерен код за верификация на сигнатурата на даден документ по даден публичен ключ:



public static boolean verifyDocumentSignature(byte[] aDocument,

PublicKey aPublicKey, byte[] aSignature)



throws GeneralSecurityException {

Signature signatureAlgorithm = Signature.getInstance("SHA1withRSA");

signatureAlgorithm.initVerify(aPublicKey);

signatureAlgorithm.update(aDocument);



boolean valid = signatureAlgorithm.verify(aSignature);

return valid;

}

java.security.cert.CertificateFactory


Класът java.security.cert.CertificateFactory
предоставя функционал­ност за зареждане на сертифи­кати, сертификационни вериги и CRL списъци от поток.

Зареждане на сертификат от поток


За прочитане на сертификат от поток или файл се използва методът CertificateFactory.generateCertificate(). Сертификатът трябва да е DER-кодиран (съгласно стандарта PKCS#7) и може да бъде представен или в бинарен или в текстов вид (с кодиране Base64).

Ето примерен код за прочитане на сертификат от стандартен .CER файл:



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

FileInputStream stream = new FileInputStream("VeriSign-Class-1-Root-CA.cer");



try {

X509Certificate cert = (X509Certificate) certFactory.generateCertificate(stream);



// Use the X.509 certificate here ...

} finally {

stream.close();

}

Зареждане на сертификационна верига


За прочитане на сертифи­ка­ционни вериги от поток се използва методът CertificateFactory.generateCertPath(). Той приема като параметър кодирането, което да бъде използвано. Допустими са кодиранията PkiPath, което отговаря на ASN.1 DER последователност от сертификати и PKCS7, което представлява PKCS#7 SignedData обект (обикновено такива обекти се записват във файлове със стандартно разширение .P7B). При изпол­зване на PKCS7 кодиране трябва да се има предвид, че при него подредбата на сертификатите от веригата не се запазва.

Ето примерен код за прочитане на сертификационна верига, съставена от X.509 сертификати, от бинарен файл с формат ASN.1 DER:



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

FileInputStream stream = new FileInputStream("chain-asn.1-der.bin");



try {

CertPath certChain = certFactory.generateCertPath(stream, "PkiPath");



// Use the certification chain here ...

} finally {

stream.close();

}

Изключенията в JCA


При извършване на операции, свързани с криптография, класовете от JCA хвърлят изключения от тип java.security.GeneralSecurityException
и java
.security.cert.CertificateException (при работа със сертификати) за да съобщят за проблем, възникнал по време на работа.

1.1.2.Директна верификация на сертификати с Java


Както знаем, за установяване на доверие между непознати страни съще­ствуват различни модели на доверие и по тази причина съществуват и различни начини за проверка на валидността на даден сертификат. Вече се запоз­нахме с два от тях – директна верификация и верификация на сертифика­ционна верига.

Директната верификация на сертификат в Java се извършва тривиално:



  • проверява се срокът на валидност на сертификата;

  • проверява се дали сертификатът е директно подписан от сертификат, на който имаме доверие.

Ето примерен сорс код, който верифицира даден сертификат по някакво предва­рително налично множество от доверени сертификати:

public static void verifyCertificate(X509Certificate aCertificate,

X509Certificate[] aTrustedCertificates)



throws GeneralSecurityException {

// First check certificate validity period

aCertificate.checkValidity();



// Check if the certificate is signed by some of the given trusted certificates

for (int i=0; iX509Certificate trustedCert = aTrustedCertificates[i];



try {

aCertificate.verify(trustedCert.getPublicKey());



// Found parent certificate. Certificate is verified to be valid

return;

}

catch (GeneralSecurityException ex) {



// Certificate is not signed by current trustedCert. Try the next one

}

}



// Cert. is not signed by any of the trusted certificates --> it is invalid

throw new CertificateValidationException(

"Can not find trusted parent certificate.");

}


Методът приключва нормално ако сертификатът е валиден или завършва с изключение, съдържащо причината за неуспех на верификацията.

1.1.3.Верификация на сертификационни вериги с Java


Класовете за проверка и построяване на сертификационни вериги се намират в Java Certification Path API
. Тази спецификация дефинира класо­вете java.security.cert.CertPath
Validator, който служи за верифи­кация на дадена сертификационна верига и java.security.cert.
CertPathBuilder, който служи за построяване на сертификационна верига по зададено множество от доверени Root-сертификати и зададено множес­тво от сертифи­кати, които могат да се използват за междинни звена в сертифика­ционната верига [Mullan, 2003].

Нека преди да разгледаме как се построяват и верифицират сертифика­ционни вериги да дадем описание на най-важните класове от Java Certification Path API.


java.security.cert.CertPath


Класът java.security.cert.CertPath представлява сертификационна вери­га (наредена последо­ва­тел­ност от сертификати).

По конвенция една правилно построена сертификационна верига започва от някакъв клиентски сертификат, следван нула или повече сертификата на междинни серти­фикационни органи и завършва с Root-сертификат на някой сертификаци­онен орган от първо ниво, като при това всеки от сертифика­тите във веригата е издаден и подписан от следващия след него.

Класът CertPath е предназначен да съхранява такива правилно построени сертификационни вериги, но може да съхранява и просто съвкупности от сертификати без те да изграждат някаква сертификационна верига.

java.security.cert.TrustAnchor


Класът java.security.cert.TrustAnchor представлява крайна точка на доверие при верификацията на сертифика­ци­онни вериги. Той се състои от публичен ключ, име на доверен сертификационен орган и съвкупност от ограничения, с които се задава множеството от пътища, което може да бъде проверявано. Обикновено тази съвкупност от ограничения се про­пуска и по подразбиране няма такива ограничения.

За простота можем да разглеждаме един TrustAnchor обект като доверен Root-сертификат, който се използва при построяване и верификация на сертификационни вериги.


java.security.cert.PKIXParameters


java.security.cert.PKIXParameters е помощен клас, който описва пара­метрите на алгоритъма PKIX, използван за верификация на сертифика­ционни вериги. Тези параметри включват списък от крайните точки на доверие за верификацията (множество от TrustAnchor обекти), датата, към която се верифицира сертификационната верига, указание дали да се използват CRL списъци и различни други настройки на алгоритъма.

java.security.cert.CertPathValidator


Най-важният клас от Java Certification Path API е java.security.cert. CertPathValidator. Той предоставя функционалност за верификация на серти­фи­ка­ци­онни вериги. Сертификационните вериги могат да бъдат съста­вени както от X.509 сертификати, така и от PGP или друг тип сертификати. За верификацията могат да се използват различни алгоритми в зависимост от модела на доверие, който се използва.

В JDK 1.5 е имплементиран стандартно единствено алгори­тъмът PKIX, който верифицира сертификационна верига съгласно организацията на инфра­структурата на публичния ключ (PKI) е описан в [RFC 3280, раздел 6]. Този алгоритъм проверява валидността на отделните сертификати и връзката между тях, като поддържа и използване на CRL списъци.


Верификация на сертификационни вериги


За верификация на сертификационна верига със стандартните средства на Java платформата се използва класът CertPathValidator. При създаването на инстанция на този клас се задава алгоритъма за верификация, който да се използва. Стандартно се поддържа единствено алгоритъмът PKIX.

При проверка на сертификационни вериги алгоритъмът PKIX започва от първия сертификат във веригата (сертифи­ката на потребителя), продъл­жава със следващия, после със следващия и т.н. и накрая завършва с последния. Необходимо е този последен сертификат от веригата да е подписан от сертификат, който е в списъка на крайните точки на доверие за верифика­цията (множеството от TrustAnchor обекти).

По спецификация веригата, която се проверява, не трябва да съдържа крайната точка от проверката, т. е. не трябва да завършва с Root-сертификата на някой сертификационен орган, а с предходния преди него. Поради тази причина, когато се прочете една сертификационна верига от някакво защитено хранилище за ключове и сертификати, преди да се започне проверката й, е необходимо от нея да се премахне последният сертификат. В противен случай е възможно проверката да пропадне, независимо, че веригата е валидна.

Методът за верификация на сертификационна верига CertPathValidator. validate() изисква като входни параметри веригата, която ще се проверява (от която е премахнат последният сертификат) и параметрите на алгоритъма за проверка. За алгоритъма PKIX тези параметри представ­ляват обект от класа PKIXParameters, който съдържа списъка от доверени Root-сертификати, в някои от които може да завършва веригата.

Ето пример за верификация на сертификационна верига с Java Certification Path API и алгоритъма PKIX:


public static void verifyCertificationChain(CertPath aCertChain,

X509Certificate[] aTrustedCACertificates)



throws GeneralSecurityException {

// Create a set of trust anchors from given trusted root CA certificates

HashSet trustAnchors = new HashSet();



for (int i = 0; i < aTrustedCACertificates.length; i++) {

TrustAnchor trustAnchor = new TrustAnchor(aTrustedCACertificates[i], null);

trustAnchors.add(trustAnchor);

}

// Create a certification chain validator and a set of parameters for it

PKIXParameters certPathValidatorParams = new PKIXParameters(trustAnchors);

certPathValidatorParams.setRevocationEnabled(false);

CertPathValidator chainValidator = CertPathValidator.getInstance("PKIX");

// Remove the root CA certificate from the end of the chain

CertPath certChainForValidation = removeLastCertFromCertChain(aCertChain);



// Execute the certification chain validation

chainValidator.validate(certChainForValidation, certPathValidatorParams);

}

private static CertPath removeLastCertFromCertChain(CertPath aCertChain)

throws CertificateException {

List certs = aCertChain.getCertificates();



int certsCount = certs.size();

List certsWithoutLast = certs.subList(0, certsCount-1);

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

CertPath certChainWithoutLastCert = cf.generateCertPath(certsWithoutLast);



return certChainWithoutLastCert;

}


В примера се верифицира сертификационна верига по дадена съвкупност от доверени Root-сертификати без да се използват CRL списъци. Необхо­димо е сертификационната верига да е налична, т. е. тя не се построява от налич­ните сертификати, а трябва да е предварително построена.

Преди извикване на метода CertPathValidator.validate(), се построява списък от TrustAnchor обекти, съдържащи на доверените Root-сертифи­кати задава се да не се ползват CRL списъци и се изтрива последния сертификат от веригата, която ще се проверява (вече обяснихме защо).

Ако вери­фикацията е успешна, методът не връща нищо, а ако веригата е невалидна, се хвърля изключение CertPathValidatorException, в което се съдържа опи­са­ние на проблема и номера на невалидния сертификат (ако има такъв).


Каталог: books -> signatures
books -> В обятията на шамбала
books -> Книга се посвещава с благодарност на децата ми. Майка ми и жена ми ме научиха да бъда мъж
books -> Николай Слатински “Надеждата като лабиринт” София, Издателство “виденов & син”, 1993 год
books -> София, Издателство “Българска книжница”, 2004 год. Рецензенти доц д. ик н. Димитър Йончев, проф д-р Нина Дюлгерова Научен редактор проф д-р Петър Иванов
books -> Николай Слатински “Измерения на сигурността” София, Издателство “Парадигма”, 2000 год
books -> Книга 2 щастие и успех предисловие
books -> Превръщане на числа от една бройна система в друга
books -> Тантриското преобразяване
signatures -> Java за цифрово подписване на документи в уеб


Сподели с приятели:
1   2   3   4   5   6   7   8   9   ...   14




©obuch.info 2024
отнасят до администрацията

    Начална страница